atp-haskell-1.7: src/Data/Logic/ATP/Lib.hs
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# OPTIONS_GHC -Wall -fno-warn-orphans -fno-warn-unused-binds #-}
module Data.Logic.ATP.Lib
( Failing(Success, Failure)
, failing
, SetLike(slView, slMap, slUnion, slEmpty, slSingleton), slInsert, prettyFoldable
, setAny
, setAll
, flatten
-- , itlist2
-- , itlist -- same as foldr with last arguments flipped
, tryfind
, tryfindM
, runRS
, evalRS
, settryfind
-- , end_itlist -- same as foldr1
, (|=>)
, (|->)
, fpf
-- * Time and timeout
, timeComputation
, timeMessage
, time
, timeout
, compete
-- * Map aliases
, defined
, undefine
, apply
-- , exists
, tryApplyD
, allpairs
, distrib
, image
, optimize
, minimize
, maximize
, can
, allsets
, allsubsets
, allnonemptysubsets
, mapfilter
, setmapfilter
, (∅)
, deepen, Depth(Depth)
, testLib
) where
import Control.Applicative (Alternative(empty, (<|>)))
import Control.Concurrent (forkIO, killThread, newEmptyMVar, putMVar, takeMVar, threadDelay)
import Control.Monad.RWS (evalRWS, runRWS, RWS)
import Data.Data (Data)
import Data.Foldable as Foldable
import Data.Function (on)
import qualified Data.List as List (map)
import Data.Map.Strict as Map (delete, findMin, insert, lookup, Map, member, singleton)
import Data.Maybe
import Data.Monoid ((<>))
import Data.Sequence as Seq (Seq, viewl, ViewL(EmptyL, (:<)), (><), singleton)
import Data.Set as Set (delete, empty, fold, fromList, insert, minView, Set, singleton, union)
import qualified Data.Set as Set (map)
import Data.Time.Clock (DiffTime, diffUTCTime, getCurrentTime, NominalDiffTime)
import Data.Typeable (Typeable)
import Debug.Trace (trace)
import Prelude hiding (map)
import System.IO (hPutStrLn, stderr)
import Text.PrettyPrint.HughesPJClass (Doc, fsep, punctuate, comma, space, Pretty(pPrint), text)
import Test.HUnit (assertEqual, Test(TestCase, TestLabel, TestList))
-- | An error idiom. Rather like the error monad, but collect all
-- errors together
data Failing a = Success a | Failure [ErrorMsg] deriving Show
type ErrorMsg = String
instance Functor Failing where
fmap _ (Failure fs) = Failure fs
fmap f (Success a) = Success (f a)
instance Applicative Failing where
pure = Success
Failure msgs <*> Failure msgs' = Failure (msgs ++ msgs')
Success _ <*> Failure msgs' = Failure msgs'
Failure msgs' <*> Success _ = Failure msgs'
Success f <*> Success x = Success (f x)
instance Alternative Failing where
empty = Failure []
(Success x) <|> _ = Success x
_ <|> (Success y) = Success y
(Failure x) <|> (Failure y) = Failure (x ++ y)
failing :: ([String] -> b) -> (a -> b) -> Failing a -> b
failing f _ (Failure errs) = f errs
failing _ f (Success a) = f a
-- Declare a Monad instance for Failing so we can chain a series of
-- Failing actions with >> or >>=. If any action fails the subsequent
-- actions in the chain will be aborted.
instance Monad Failing where
return = Success
m >>= f =
case m of
(Failure errs) -> (Failure errs)
(Success a) -> f a
fail errMsg = Failure [errMsg]
deriving instance Typeable Failing
deriving instance Data a => Data (Failing a)
deriving instance Read a => Read (Failing a)
deriving instance Eq a => Eq (Failing a)
deriving instance Ord a => Ord (Failing a)
instance Pretty a => Pretty (Failing a) where
pPrint (Failure ss) = text (unlines ("Failures:" : List.map (" " ++) ss))
pPrint (Success a) = pPrint a
-- | A simple class, slightly more powerful than Foldable, so we can
-- write functions that operate on the elements of a set or a list.
class Foldable c => SetLike c where
slView :: forall a. c a -> Maybe (a, c a)
slMap :: forall a b. Ord b => (a -> b) -> c a -> c b
slUnion :: Ord a => c a -> c a -> c a
slEmpty :: c a
slSingleton :: a -> c a
instance SetLike Set where
slView = Set.minView
slMap = Set.map
slUnion = Set.union
slEmpty = Set.empty
slSingleton = Set.singleton
instance SetLike [] where
slView [] = Nothing
slView (h : t) = Just (h, t)
slMap = List.map
slUnion = (<>)
slEmpty = mempty
slSingleton = (: [])
instance SetLike Seq where
slView s = case viewl s of
EmptyL -> Nothing
h :< t -> Just (h, t)
slMap = fmap
slUnion = (><)
slEmpty = mempty
slSingleton = Seq.singleton
slInsert :: (SetLike set, Ord a) => a -> set a -> set a
slInsert x s = slUnion (slSingleton x) s
prettyFoldable :: (Foldable t, Pretty a) => t a -> Doc
prettyFoldable s = fsep (punctuate (comma <> space) (List.map pPrint (Foldable.foldr (:) [] s)))
--instance (Pretty a, SetLike set) => Pretty (set a) where
-- pPrint = prettyFoldable
(∅) :: (Monoid (c a), SetLike c) => c a
(∅) = mempty
setAny :: Foldable t => (a -> Bool) -> t a -> Bool
setAny = any
setAll :: Foldable t => (a -> Bool) -> t a -> Bool
setAll = all
flatten :: Ord a => Set (Set a) -> Set a
flatten ss' = Set.fold Set.union Set.empty ss'
{-
(* ========================================================================= *)
(* Misc library functions to set up a nice environment. *)
(* ========================================================================= *)
let identity x = x;;
let ( ** ) = fun f g x -> f(g x);;
(* ------------------------------------------------------------------------- *)
(* GCD and LCM on arbitrary-precision numbers. *)
(* ------------------------------------------------------------------------- *)
let gcd_num n1 n2 =
abs_num(num_of_big_int
(Big_int.gcd_big_int (big_int_of_num n1) (big_int_of_num n2)));;
let lcm_num n1 n2 = abs_num(n1 */ n2) // gcd_num n1 n2;;
(* ------------------------------------------------------------------------- *)
(* A useful idiom for "non contradictory" etc. *)
(* ------------------------------------------------------------------------- *)
let non p x = not(p x);;
(* ------------------------------------------------------------------------- *)
(* Kind of assertion checking. *)
(* ------------------------------------------------------------------------- *)
let check p x = if p(x) then x else failwith "check";;
(* ------------------------------------------------------------------------- *)
(* Repetition of a function. *)
(* ------------------------------------------------------------------------- *)
let rec funpow n f x =
if n < 1 then x else funpow (n-1) f (f x);;
-}
-- let can f x = try f x; true with Failure _ -> false;;
can :: (t -> Failing a) -> t -> Bool
can f x = failing (const True) (const False) (f x)
{-
let rec repeat f x = try repeat f (f x) with Failure _ -> x;;
(* ------------------------------------------------------------------------- *)
(* Handy list operations. *)
(* ------------------------------------------------------------------------- *)
let rec (--) = fun m n -> if m > n then [] else m::((m + 1) -- n);;
let rec (---) = fun m n -> if m >/ n then [] else m::((m +/ Int 1) --- n);;
let rec map2 f l1 l2 =
match (l1,l2) with
[],[] -> []
| (h1::t1),(h2::t2) -> let h = f h1 h2 in h::(map2 f t1 t2)
| _ -> failwith "map2: length mismatch";;
let rev =
let rec rev_append acc l =
match l with
[] -> acc
| h::t -> rev_append (h::acc) t in
fun l -> rev_append [] l;;
let hd l =
match l with
h::t -> h
| _ -> failwith "hd";;
let tl l =
match l with
h::t -> t
| _ -> failwith "tl";;
-}
-- (^) = (++)
itlist :: Foldable t => (a -> b -> b) -> t a -> b -> b
itlist f xs z = Foldable.foldr f z xs
end_itlist :: Foldable t => (a -> a -> a) -> t a -> a
end_itlist = Foldable.foldr1
itlist2 :: (SetLike s, SetLike t) =>
(a -> b -> Failing r -> Failing r) ->
s a -> t b -> Failing r -> Failing r
itlist2 f s t r =
case (slView s, slView t) of
(Nothing, Nothing) -> r
(Just (a, s'), Just (b, t')) ->
f a b (itlist2 f s' t' r)
_ -> Failure ["itlist2"]
{-
let rec zip l1 l2 =
match (l1,l2) with
([],[]) -> []
| (h1::t1,h2::t2) -> (h1,h2)::(zip t1 t2)
| _ -> failwith "zip";;
let rec forall p l =
match l with
[] -> true
| h::t -> p(h) & forall p t;;
-}
exists :: Foldable t => (a -> Bool) -> t a -> Bool
exists = any
{-
let partition p l =
itlist (fun a (yes,no) -> if p a then a::yes,no else yes,a::no) l ([],[]);;
let filter p l = fst(partition p l);;
let length =
let rec len k l =
if l = [] then k else len (k + 1) (tl l) in
fun l -> len 0 l;;
let rec last l =
match l with
[x] -> x
| (h::t) -> last t
| [] -> failwith "last";;
let rec butlast l =
match l with
[_] -> []
| (h::t) -> h::(butlast t)
| [] -> failwith "butlast";;
let rec find p l =
match l with
[] -> failwith "find"
| (h::t) -> if p(h) then h else find p t;;
let rec el n l =
if n = 0 then hd l else el (n - 1) (tl l);;
let map f =
let rec mapf l =
match l with
[] -> []
| (x::t) -> let y = f x in y::(mapf t) in
mapf;;
-}
-- allpairs :: forall a b c. (Ord c) => (a -> b -> c) -> Set a -> Set b -> Set c
-- allpairs f xs ys = Set.fold (\ x zs -> Set.fold (\ y zs' -> Set.insert (f x y) zs') zs ys) Set.empty xs
allpairs :: forall a b c set. (SetLike set, Ord c) => (a -> b -> c) -> set a -> set b -> set c
allpairs f xs ys = Foldable.foldr (\ x zs -> Foldable.foldr (g x) zs ys) slEmpty xs
where g :: a -> b -> set c -> set c
g x y zs' = slInsert (f x y) zs'
distrib :: Ord a => Set (Set a) -> Set (Set a) -> Set (Set a)
distrib s1 s2 = allpairs (Set.union) s1 s2
test01 :: Test
test01 = TestCase $ assertEqual "allpairs" expected input
where input = allpairs (,) (Set.fromList [1,2,3]) (Set.fromList [4,5,6])
expected = Set.fromList [(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)] :: Set (Int, Int)
{-
let rec distinctpairs l =
match l with
x::t -> itlist (fun y a -> (x,y) :: a) t (distinctpairs t)
| [] -> [];;
let rec chop_list n l =
if n = 0 then [],l else
try let m,l' = chop_list (n-1) (tl l) in (hd l)::m,l'
with Failure _ -> failwith "chop_list";;
let replicate n a = map (fun x -> a) (1--n);;
let rec insertat i x l =
if i = 0 then x::l else
match l with
[] -> failwith "insertat: list too short for position to exist"
| h::t -> h::(insertat (i-1) x t);;
let rec forall2 p l1 l2 =
match (l1,l2) with
[],[] -> true
| (h1::t1,h2::t2) -> p h1 h2 & forall2 p t1 t2
| _ -> false;;
let index x =
let rec ind n l =
match l with
[] -> failwith "index"
| (h::t) -> if Pervasives.compare x h = 0 then n else ind (n + 1) t in
ind 0;;
let rec unzip l =
match l with
[] -> [],[]
| (x,y)::t ->
let xs,ys = unzip t in x::xs,y::ys;;
(* ------------------------------------------------------------------------- *)
(* Whether the first of two items comes earlier in the list. *)
(* ------------------------------------------------------------------------- *)
let rec earlier l x y =
match l with
h::t -> (Pervasives.compare h y <> 0) &
(Pervasives.compare h x = 0 or earlier t x y)
| [] -> false;;
(* ------------------------------------------------------------------------- *)
(* Application of (presumably imperative) function over a list. *)
(* ------------------------------------------------------------------------- *)
let rec do_list f l =
match l with
[] -> ()
| h::t -> f(h); do_list f t;;
(* ------------------------------------------------------------------------- *)
(* Association lists. *)
(* ------------------------------------------------------------------------- *)
let rec assoc a l =
match l with
(x,y)::t -> if Pervasives.compare x a = 0 then y else assoc a t
| [] -> failwith "find";;
let rec rev_assoc a l =
match l with
(x,y)::t -> if Pervasives.compare y a = 0 then x else rev_assoc a t
| [] -> failwith "find";;
(* ------------------------------------------------------------------------- *)
(* Merging of sorted lists (maintaining repetitions). *)
(* ------------------------------------------------------------------------- *)
let rec merge ord l1 l2 =
match l1 with
[] -> l2
| h1::t1 -> match l2 with
[] -> l1
| h2::t2 -> if ord h1 h2 then h1::(merge ord t1 l2)
else h2::(merge ord l1 t2);;
(* ------------------------------------------------------------------------- *)
(* Bottom-up mergesort. *)
(* ------------------------------------------------------------------------- *)
let sort ord =
let rec mergepairs l1 l2 =
match (l1,l2) with
([s],[]) -> s
| (l,[]) -> mergepairs [] l
| (l,[s1]) -> mergepairs (s1::l) []
| (l,(s1::s2::ss)) -> mergepairs ((merge ord s1 s2)::l) ss in
fun l -> if l = [] then [] else mergepairs [] (map (fun x -> [x]) l);;
(* ------------------------------------------------------------------------- *)
(* Common measure predicates to use with "sort". *)
(* ------------------------------------------------------------------------- *)
let increasing f x y = Pervasives.compare (f x) (f y) < 0;;
let decreasing f x y = Pervasives.compare (f x) (f y) > 0;;
(* ------------------------------------------------------------------------- *)
(* Eliminate repetitions of adjacent elements, with and without counting. *)
(* ------------------------------------------------------------------------- *)
let rec uniq l =
match l with
x::(y::_ as t) -> let t' = uniq t in
if Pervasives.compare x y = 0 then t' else
if t'==t then l else x::t'
| _ -> l;;
let repetitions =
let rec repcount n l =
match l with
x::(y::_ as ys) -> if Pervasives.compare y x = 0 then repcount (n + 1) ys
else (x,n)::(repcount 1 ys)
| [x] -> [x,n]
| [] -> failwith "repcount" in
fun l -> if l = [] then [] else repcount 1 l;;
-}
tryfind :: Foldable t => (a -> Failing r) -> t a -> Failing r
tryfind p s = maybe (Failure ["tryfind"]) p (find (failing (const False) (const True) . p) s)
tryfindM :: Monad m => (t -> m (Failing a)) -> [t] -> m (Failing a)
tryfindM _ [] = return $ Failure ["tryfindM"]
tryfindM f (h : t) = f h >>= failing (\_ -> tryfindM f t) (return . Success)
evalRS :: RWS r () s a -> r -> s -> a
evalRS action r s = fst $ evalRWS action r s
runRS :: RWS r () s a -> r -> s -> (a, s)
runRS action r s = (\(a, s', _w) -> (a, s')) $ runRWS action r s
test02 :: Test
test02 =
TestCase $
assertEqual
"tryfind on infinite list"
(Success 3 :: Failing Int)
(tryfind (\x -> if x == 3
then Success 3
else Failure ["test02"]) ([1..] :: [Int]))
settryfind :: (t -> Failing a) -> Set t -> Failing a
settryfind f l =
case Set.minView l of
Nothing -> Failure ["settryfind"]
Just (h, t) -> failing (\ _ -> settryfind f t) Success (f h)
mapfilter :: (a -> Failing b) -> [a] -> [b]
mapfilter f l = catMaybes (List.map (failing (const Nothing) Just . f) l)
-- filter (failing (const False) (const True)) (map f l)
setmapfilter :: Ord b => (a -> Failing b) -> Set a -> Set b
setmapfilter f s = Set.fold (\ a r -> failing (const r) (`Set.insert` r) (f a)) Set.empty s
-- -------------------------------------------------------------------------
-- Find list member that maximizes or minimizes a function.
-- -------------------------------------------------------------------------
optimize :: forall s a b. (SetLike s, Foldable s) => (b -> b -> Ordering) -> (a -> b) -> s a -> Maybe a
optimize _ _ l | isNothing (slView l) = Nothing
optimize ord f l = Just (Foldable.maximumBy (ord `on` f) l)
maximize :: (Ord b, SetLike s, Foldable s) => (a -> b) -> s a -> Maybe a
maximize = optimize compare
minimize :: (Ord b, SetLike s, Foldable s) => (a -> b) -> s a -> Maybe a
minimize = optimize (flip compare)
-- -------------------------------------------------------------------------
-- Set operations on ordered lists.
-- -------------------------------------------------------------------------
{-
let setify =
let rec canonical lis =
match lis with
x::(y::_ as rest) -> Pervasives.compare x y < 0 & canonical rest
| _ -> true in
fun l -> if canonical l then l
else uniq (sort (fun x y -> Pervasives.compare x y <= 0) l);;
let union =
let rec union l1 l2 =
match (l1,l2) with
([],l2) -> l2
| (l1,[]) -> l1
| ((h1::t1 as l1),(h2::t2 as l2)) ->
if h1 = h2 then h1::(union t1 t2)
else if h1 < h2 then h1::(union t1 l2)
else h2::(union l1 t2) in
fun s1 s2 -> union (setify s1) (setify s2);;
let intersect =
let rec intersect l1 l2 =
match (l1,l2) with
([],l2) -> []
| (l1,[]) -> []
| ((h1::t1 as l1),(h2::t2 as l2)) ->
if h1 = h2 then h1::(intersect t1 t2)
else if h1 < h2 then intersect t1 l2
else intersect l1 t2 in
fun s1 s2 -> intersect (setify s1) (setify s2);;
let subtract =
let rec subtract l1 l2 =
match (l1,l2) with
([],l2) -> []
| (l1,[]) -> l1
| ((h1::t1 as l1),(h2::t2 as l2)) ->
if h1 = h2 then subtract t1 t2
else if h1 < h2 then h1::(subtract t1 l2)
else subtract l1 t2 in
fun s1 s2 -> subtract (setify s1) (setify s2);;
let subset,psubset =
let rec subset l1 l2 =
match (l1,l2) with
([],l2) -> true
| (l1,[]) -> false
| (h1::t1,h2::t2) ->
if h1 = h2 then subset t1 t2
else if h1 < h2 then false
else subset l1 t2
and psubset l1 l2 =
match (l1,l2) with
(l1,[]) -> false
| ([],l2) -> true
| (h1::t1,h2::t2) ->
if h1 = h2 then psubset t1 t2
else if h1 < h2 then false
else subset l1 t2 in
(fun s1 s2 -> subset (setify s1) (setify s2)),
(fun s1 s2 -> psubset (setify s1) (setify s2));;
let rec set_eq s1 s2 = (setify s1 = setify s2);;
let insert x s = union [x] s;;
-}
image :: (Ord b, Ord a) => (a -> b) -> Set a -> Set b
image f s = Set.map f s
{-
(* ------------------------------------------------------------------------- *)
(* Union of a family of sets. *)
(* ------------------------------------------------------------------------- *)
let unions s = setify(itlist (@) s []);;
(* ------------------------------------------------------------------------- *)
(* List membership. This does *not* assume the list is a set. *)
(* ------------------------------------------------------------------------- *)
let rec mem x lis =
match lis with
[] -> false
| (h::t) -> Pervasives.compare x h = 0 or mem x t;;
-}
-- -------------------------------------------------------------------------
-- Finding all subsets or all subsets of a given size.
-- -------------------------------------------------------------------------
-- allsets :: Ord a => Int -> Set a -> Set (Set a)
allsets :: forall a b. (Num a, Eq a, Ord b) => a -> Set b -> Set (Set b)
allsets 0 _ = Set.singleton Set.empty
allsets m l =
case Set.minView l of
Nothing -> Set.empty
Just (h, t) -> Set.union (Set.map (Set.insert h) (allsets (m - 1) t)) (allsets m t)
allsubsets :: forall a. Ord a => Set a -> Set (Set a)
allsubsets s =
maybe (Set.singleton Set.empty)
(\ (x, t) ->
let res = allsubsets t in
Set.union res (Set.map (Set.insert x) res))
(Set.minView s)
allnonemptysubsets :: forall a. Ord a => Set a -> Set (Set a)
allnonemptysubsets s = Set.delete Set.empty (allsubsets s)
{-
(* ------------------------------------------------------------------------- *)
(* Explosion and implosion of strings. *)
(* ------------------------------------------------------------------------- *)
let explode s =
let rec exap n l =
if n < 0 then l else
exap (n - 1) ((String.sub s n 1)::l) in
exap (String.length s - 1) [];;
let implode l = itlist (^) l "";;
(* ------------------------------------------------------------------------- *)
(* Timing; useful for documentation but not logically necessary. *)
(* ------------------------------------------------------------------------- *)
let time f x =
let start_time = Sys.time() in
let result = f x in
let finish_time = Sys.time() in
print_string
("CPU time (user): "^(string_of_float(finish_time -. start_time)));
print_newline();
result;;
-}
-- | Perform an IO operation and return the elapsed time along with the result.
timeComputation :: IO r -> IO (r, NominalDiffTime)
timeComputation a = do
start <- getCurrentTime
r <- a
end <- getCurrentTime
return (r, diffUTCTime end start)
-- | Perform an IO operation and output a message about how long it took.
timeMessage :: (r -> NominalDiffTime -> String) -> IO r -> IO r
timeMessage pp a = do
(r, e) <- timeComputation a
hPutStrLn stderr (pp r e)
return r
-- | Output elapsed time
time :: IO r -> IO r
time a = timeMessage (\_ e -> "Computation time: " ++ show e) a
-- | Allow a computation to proceed for a given amount of time.
timeout :: String -> DiffTime -> IO r -> IO (Either String r)
timeout message delay a = do
compete [threadDelay (fromEnum (realToFrac (delay / 1e6) :: Rational)) >> return (Left message),
Right <$> a]
-- | Run several IO operations in parallel, return the result of the
-- first one that completes and kill the others.
compete :: [IO a] -> IO a
compete actions = do
mvar <- newEmptyMVar
tids <- mapM (\action -> forkIO $ action >>= putMVar mvar) actions
result <- takeMVar mvar
mapM_ killThread tids
return result
-- | Polymorphic finite partial functions via Patricia trees.
--
-- The point of this strange representation is that it is canonical (equal
-- functions have the same encoding) yet reasonably efficient on average.
--
-- Idea due to Diego Olivier Fernandez Pons (OCaml list, 2003/11/10).
data Func a b
= Empty
| Leaf Int [(a, b)]
| Branch Int Int (Func a b) (Func a b)
-- | Undefined function.
undefinedFunction :: Func a b
undefinedFunction = Empty
-- -------------------------------------------------------------------------
-- In case of equality comparison worries, better use this.
-- -------------------------------------------------------------------------
isUndefined :: Func a b -> Bool
isUndefined Empty = True
isUndefined _ = False
-- -------------------------------------------------------------------------
-- Operation analogous to "map" for functions.
-- -------------------------------------------------------------------------
mapf :: (b -> c) -> Func a b -> Func a c
mapf f t =
case t of
Empty -> Empty
Leaf h l -> Leaf h (map_list f l)
Branch p b l r -> Branch p b (mapf f l) (mapf f r)
where
map_list f' l' =
case l' of
[] -> []
(x,y) : t' -> (x, f' y) : map_list f' t'
-- -------------------------------------------------------------------------
-- Operations analogous to "fold" for lists.
-- -------------------------------------------------------------------------
foldlFn :: (r -> a -> b -> r) -> r -> Func a b -> r
foldlFn f a t =
case t of
Empty -> a
Leaf _h l -> foldl_list f a l
Branch _p _b l r -> foldlFn f (foldlFn f a l) r
where
foldl_list _f a' l =
case l of
[] -> a'
(x,y) : t' -> foldl_list f (f a' x y) t'
foldrFn :: (a -> b -> r -> r) -> Func a b -> r -> r
foldrFn f t a =
case t of
Empty -> a
Leaf _h l -> foldr_list f l a
Branch _p _b l r -> foldrFn f l (foldrFn f r a)
where
foldr_list f' l a' =
case l of
[] -> a'
(x, y) : t' -> f' x y (foldr_list f' t' a')
-- -------------------------------------------------------------------------
-- Mapping to sorted-list representation of the graph, domain and range.
-- -------------------------------------------------------------------------
graph :: (Ord a, Ord b) => Func a b -> Set (a, b)
graph f = Set.fromList (foldlFn (\ a x y -> (x,y) : a) [] f)
dom :: Ord a => Func a b -> Set a
dom f = Set.fromList (foldlFn (\ a x _y -> x :a) [] f)
ran :: Ord b => Func a b -> Set b
ran f = Set.fromList (foldlFn (\ a _x y -> y : a) [] f)
-- -------------------------------------------------------------------------
-- Application.
-- -------------------------------------------------------------------------
applyD :: Ord k => Map k a -> k -> a -> Map k a
applyD m k a = Map.insert k a m
apply :: Ord k => Map k a -> k -> Maybe a
apply m k = Map.lookup k m
tryApplyD :: Ord k => Map k a -> k -> a -> a
tryApplyD m k d = fromMaybe d (Map.lookup k m)
tryApplyL :: Ord k => Map k [a] -> k -> [a]
tryApplyL m k = tryApplyD m k []
{-
applyD :: (t -> Maybe b) -> (t -> b) -> t -> b
applyD f d x = maybe (d x) id (f x)
apply :: (t -> Maybe b) -> t -> b
apply f = applyD f (\ _ -> error "apply")
tryApplyD :: (t -> Maybe b) -> t -> b -> b
tryApplyD f a d = maybe d id (f a)
tryApplyL :: (t -> Maybe [a]) -> t -> [a]
tryApplyL f x = tryApplyD f x []
-}
defined :: Ord t => Map t a -> t -> Bool
defined = flip Map.member
-- | Undefinition.
undefine :: forall k a. Ord k => k -> Map k a -> Map k a
undefine k mp = Map.delete k mp
{-
(* ------------------------------------------------------------------------- *)
(* Redefinition and combination. *)
(* ------------------------------------------------------------------------- *)
let (|->),combine =
let newbranch p1 t1 p2 t2 =
let zp = p1 lxor p2 in
let b = zp land (-zp) in
let p = p1 land (b - 1) in
if p1 land b = 0 then Branch(p,b,t1,t2)
else Branch(p,b,t2,t1) in
let rec define_list (x,y as xy) l =
match l with
(a,b as ab)::t ->
let c = Pervasives.compare x a in
if c = 0 then xy::t
else if c < 0 then xy::l
else ab::(define_list xy t)
| [] -> [xy]
and combine_list op z l1 l2 =
match (l1,l2) with
[],_ -> l2
| _,[] -> l1
| ((x1,y1 as xy1)::t1,(x2,y2 as xy2)::t2) ->
let c = Pervasives.compare x1 x2 in
if c < 0 then xy1::(combine_list op z t1 l2)
else if c > 0 then xy2::(combine_list op z l1 t2) else
let y = op y1 y2 and l = combine_list op z t1 t2 in
if z(y) then l else (x1,y)::l in
let (|->) x y =
let k = Hashtbl.hash x in
let rec upd t =
match t with
Empty -> Leaf (k,[x,y])
| Leaf(h,l) ->
if h = k then Leaf(h,define_list (x,y) l)
else newbranch h t k (Leaf(k,[x,y]))
| Branch(p,b,l,r) ->
if k land (b - 1) <> p then newbranch p t k (Leaf(k,[x,y]))
else if k land b = 0 then Branch(p,b,upd l,r)
else Branch(p,b,l,upd r) in
upd in
let rec combine op z t1 t2 =
match (t1,t2) with
Empty,_ -> t2
| _,Empty -> t1
| Leaf(h1,l1),Leaf(h2,l2) ->
if h1 = h2 then
let l = combine_list op z l1 l2 in
if l = [] then Empty else Leaf(h1,l)
else newbranch h1 t1 h2 t2
| (Leaf(k,lis) as lf),(Branch(p,b,l,r) as br) ->
if k land (b - 1) = p then
if k land b = 0 then
(match combine op z lf l with
Empty -> r | l' -> Branch(p,b,l',r))
else
(match combine op z lf r with
Empty -> l | r' -> Branch(p,b,l,r'))
else
newbranch k lf p br
| (Branch(p,b,l,r) as br),(Leaf(k,lis) as lf) ->
if k land (b - 1) = p then
if k land b = 0 then
(match combine op z l lf with
Empty -> r | l' -> Branch(p,b,l',r))
else
(match combine op z r lf with
Empty -> l | r' -> Branch(p,b,l,r'))
else
newbranch p br k lf
| Branch(p1,b1,l1,r1),Branch(p2,b2,l2,r2) ->
if b1 < b2 then
if p2 land (b1 - 1) <> p1 then newbranch p1 t1 p2 t2
else if p2 land b1 = 0 then
(match combine op z l1 t2 with
Empty -> r1 | l -> Branch(p1,b1,l,r1))
else
(match combine op z r1 t2 with
Empty -> l1 | r -> Branch(p1,b1,l1,r))
else if b2 < b1 then
if p1 land (b2 - 1) <> p2 then newbranch p1 t1 p2 t2
else if p1 land b2 = 0 then
(match combine op z t1 l2 with
Empty -> r2 | l -> Branch(p2,b2,l,r2))
else
(match combine op z t1 r2 with
Empty -> l2 | r -> Branch(p2,b2,l2,r))
else if p1 = p2 then
(match (combine op z l1 l2,combine op z r1 r2) with
(Empty,r) -> r | (l,Empty) -> l | (l,r) -> Branch(p1,b1,l,r))
else
newbranch p1 t1 p2 t2 in
(|->),combine;;
-}
-- -------------------------------------------------------------------------
-- Special case of point function.
-- -------------------------------------------------------------------------
(|=>) :: Ord k => k -> a -> Map k a
x |=> y = Map.singleton x y
-- -------------------------------------------------------------------------
-- Idiom for a mapping zipping domain and range lists.
-- -------------------------------------------------------------------------
(|->) :: Ord k => k -> a -> Map k a -> Map k a
(|->) = Map.insert
fpf :: Ord a => Map a b -> a -> Maybe b
fpf = flip Map.lookup
-- -------------------------------------------------------------------------
-- Grab an arbitrary element.
-- -------------------------------------------------------------------------
choose :: Map k a -> (k, a)
choose = Map.findMin
{-
(* ------------------------------------------------------------------------- *)
(* Install a (trivial) printer for finite partial functions. *)
(* ------------------------------------------------------------------------- *)
let print_fpf (f:('a,'b)func) = print_string "<func>";;
#install_printer print_fpf;;
(* ------------------------------------------------------------------------- *)
(* Related stuff for standard functions. *)
(* ------------------------------------------------------------------------- *)
let valmod a y f x = if x = a then y else f(x);;
let undef x = failwith "undefined function";;
(* ------------------------------------------------------------------------- *)
(* Union-find algorithm. *)
(* ------------------------------------------------------------------------- *)
type ('a)pnode = Nonterminal of 'a | Terminal of 'a * int;;
type ('a)partition = Partition of ('a,('a)pnode)func;;
let rec terminus (Partition f as ptn) a =
match (apply f a) with
Nonterminal(b) -> terminus ptn b
| Terminal(p,q) -> (p,q);;
let tryterminus ptn a =
try terminus ptn a with Failure _ -> (a,1);;
let canonize ptn a = fst(tryterminus ptn a);;
let equivalent eqv a b = canonize eqv a = canonize eqv b;;
let equate (a,b) (Partition f as ptn) =
let (a',na) = tryterminus ptn a
and (b',nb) = tryterminus ptn b in
Partition
(if a' = b' then f else
if na <= nb then
itlist identity [a' |-> Nonterminal b'; b' |-> Terminal(b',na+nb)] f
else
itlist identity [b' |-> Nonterminal a'; a' |-> Terminal(a',na+nb)] f);;
let unequal = Partition undefined;;
let equated (Partition f) = dom f;;
(* ------------------------------------------------------------------------- *)
(* First number starting at n for which p succeeds. *)
(* ------------------------------------------------------------------------- *)
let rec first n p = if p(n) then n else first (n +/ Int 1) p;;
-}
-- | Try f with higher and higher values of n until it succeeds, or
-- optional maximum depth limit is exceeded.
{-
let rec deepen f n =
try print_string "Searching with depth limit ";
print_int n; print_newline(); f n
with Failure _ -> deepen f (n + 1);;
-}
deepen :: (Depth -> Failing t) -> Depth -> Maybe Depth -> Failing (t, Depth)
deepen _ n (Just m) | n > m = Failure ["Exceeded maximum depth limit"]
deepen f n m =
-- If no maximum depth limit is given print a trace of the
-- levels tried. The assumption is that we are running
-- interactively.
let n' = maybe (trace ("Searching with depth limit " ++ show n) n) (\_ -> n) m in
case f n' of
Failure _ -> deepen f (succ n) m
Success x -> Success (x, n)
newtype Depth = Depth Int deriving (Eq, Ord, Show)
instance Enum Depth where
toEnum = Depth
fromEnum (Depth n) = n
instance Pretty Depth where
pPrint = text . show
testLib :: Test
testLib = TestLabel "Lib" (TestList [test01])