#
# spec file for package ChasingBottoms
#
# Copyright (c) 2018 SUSE LINUX GmbH, Nuernberg, Germany.
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
# upon. The license for this file, and modifications and additions to the
# file, is the same license as for the pristine package itself (unless the
# license for the pristine package is not an Open Source License, in which
# case the license is the MIT License). An "Open Source License" is a
# license that conforms to the Open Source Definition (Version 1.9)
# published by the Open Source Initiative.
# Please submit bugfixes or comments via http://bugs.opensuse.org/
#
%global pkg_name ChasingBottoms
%bcond_with tests
Name: %{pkg_name}
Version: 1.3.1.3
Release: 0
Summary: For testing partial and infinite values
License: MIT
Group: Development/Libraries/Haskell
URL: https://hackage.haskell.org/package/%{name}
Source0: https://hackage.haskell.org/package/%{name}-%{version}/%{name}-%{version}.tar.gz
BuildRequires: ghc-Cabal-devel
BuildRequires: ghc-QuickCheck-devel
BuildRequires: ghc-containers-devel
BuildRequires: ghc-mtl-devel
BuildRequires: ghc-random-devel
BuildRequires: ghc-rpm-macros
BuildRequires: ghc-syb-devel
%if %{with tests}
BuildRequires: ghc-array-devel
%endif
%description
Do you ever feel the need to test code involving bottoms (e.g. calls to the
'error' function), or code involving infinite values? Then this library could
be useful for you.
It is usually easy to get a grip on bottoms by showing a value and waiting to
see how much gets printed before the first exception is encountered.
However, that quickly gets tiresome and is hard to automate using e.g.
QuickCheck (). With this library
you can do the tests as simply as the following examples show.
Testing explicitly for bottoms:
> > isBottom (head []) > True
> > isBottom bottom > True
> > isBottom (_ -> bottom) > False
> > isBottom (bottom, bottom) > False
Comparing finite, partial values:
> > ((bottom, 3) :: (Bool, Int)) ==! (bottom, 2+5-4) > True
> > ((bottom, bottom) :: (Bool, Int)) True
Showing partial and infinite values ('\/!' is join and '/\!' is meet):
> > approxShow 4 $ (True, bottom) /! (bottom, 'b') > "Just (True, 'b')"
> > approxShow 4 $ (True, bottom) /! (bottom, 'b') > "(_|_, _|_)"
> > approxShow 4 $ ([1..] :: [Int]) > "[1, 2, 3, _"
> > approxShow 4 $ (cycle [bottom] :: [Bool]) > "[_|_, _|_, _|_, _"
Approximately comparing infinite, partial values:
> > approx 100 [2,4..] ==! approx 100 (filter even [1..] :: [Int]) > True
> > approx 100 [2,4..] /=! approx 100 (filter even [bottom..] :: [Int]) > True
The code above relies on the fact that 'bottom', just as 'error "..."',
'undefined' and pattern match failures, yield exceptions. Sometimes we are
dealing with properly non-terminating computations, such as the following
example, and then it can be nice to be able to apply a time-out:
> > timeOut' 1 (reverse [1..5]) > Value [5,4,3,2,1]
> > timeOut' 1 (reverse [1..]) > NonTermination
The time-out functionality can be used to treat "slow" computations as bottoms:
' > let tweak = Tweak { approxDepth = Just 5, timeOutLimit = Just 2 }
> semanticEq tweak (reverse [1..], [1..]) (bottom :: [Int], [1..] :: [Int])
True '
' > let tweak = noTweak { timeOutLimit = Just 2 } > semanticJoin
tweak (reverse [1..], True) ([] :: [Int], bottom) Just ([],True) '
This can of course be dangerous:
' > let tweak = noTweak { timeOutLimit = Just 0 } > semanticEq tweak
(reverse [1..100000000]) (bottom :: [Integer]) True '
Timeouts can also be applied to 'IO' computations:
> > let primes () = unfoldr ((x:xs) -> Just (x, filter ((/= 0) .
(`mod` x)) xs)) [2..] > > timeOutMicro 100 (print $ primes ()) >
[2,NonTermination > > timeOutMicro 10000 (print $ take 10 $ primes ()) >
[2,3,5,7,11,13,17,19,23,29] > Value ()
For the underlying theory and a larger example involving use of QuickCheck, see
the article "Chasing Bottoms, A Case Study in Program Verification in the
Presence of Partial and Infinite Values"
().
The code has been tested using GHC. Most parts can probably be ported to other
Haskell compilers, but this would require some work. The 'TimeOut' functions
require preemptive scheduling, and most of the rest requires 'Data.Generics';
'isBottom' only requires exceptions, though.
%package -n ghc-%{name}
Summary: Haskell %{name} library
Group: System/Libraries
%description -n ghc-%{name}
This package provides the Haskell %{name} shared library.
%package -n ghc-%{name}-devel
Summary: Haskell %{name} library development files
Group: Development/Libraries/Haskell
Requires: ghc-%{name} = %{version}-%{release}
Requires: ghc-compiler = %{ghc_version}
Requires(post): ghc-compiler = %{ghc_version}
Requires(postun): ghc-compiler = %{ghc_version}
%description -n ghc-%{name}-devel
This package provides the Haskell %{name} library development files.
%prep
%setup -q
%build
%ghc_lib_build
%install
%ghc_lib_install
%check
%cabal_test
%post -n ghc-%{name}-devel
%ghc_pkg_recache
%postun -n ghc-%{name}-devel
%ghc_pkg_recache
%files
%license LICENCE
%files -n ghc-%{name} -f ghc-%{name}.files
%license LICENCE
%files -n ghc-%{name}-devel -f ghc-%{name}-devel.files
%changelog