packages feed

Craft3e 0.1.0.5 → 0.1.0.6

raw patch · 11 files changed

+133/−996 lines, 11 filesbinary-added

Files

.DS_Store view

binary file changed (6148 → 6148 bytes)

Chapter15/.DS_Store view

binary file changed (6148 → 6148 bytes)

− Chapter15/Solutions15.hs
@@ -1,212 +0,0 @@------------------------------------------------------------------------------------- 	Haskell: The Craft of Functional Programming--- 	Simon Thompson--- 	(c) Addison-Wesley, 2011.--- --- 	Solutions15------------------------------------------------------------------------------------module Solutions15 where--import Types------- Solution 15.1------- It is always possible to limit what is imported from a particular--- module through import controls, but that doesn't prevent a client of --- the imported module importing anything from the client, if no export--- controls are in place.---- On the other hand, export controls are needed for re-export of imported--- definitions, which are not re-exported by default.---- Export controls have an annoying limitation: it's not possible to hide--- particular bindings explicitly on export, rather have to have a whole export--- list which excludes the binding(s) in question, but which has to include--- everything else.------- Solution 15.2------- It's the right default: can always re-export, but if everything re-exported a--- automatically it's harder to look at a module and see where the definitions it --- uses come from. As it stands, a definition will be in one of the modules included,--- or explicitly re-exported from one of those.---- Also auto re-export would possibly pollute the name space with bindings we don't--- want to be aware of.------- Solution 15.3------- More brevity. Why not? Could have to check consistency: what if we say "no Dog"--- but something imported from Dog is explicitly exported?------- Solution 15.4------- LRLRRRRRLRR------- Solution 15.5------- babbat---- would expect that the shortest is with b coded by a single letter; using the--- tree in 15.4 get the coding LRLLLRLRR: 9 chars rather than 10.------- Solutions 15.6-7------- Just walk through the definitions------- Solution 15.8-----mergeSort :: Ord a => [a] -> [a]--mergeSort [] = []--mergeSort [x] = [x]--mergeSort xs -  = mergeOrd (mergeSort left) (mergeSort right) -    where-    (left,right) = splitAt (length xs `div` 2) xs--mergeOrd :: Ord a => [a] -> [a] -> [a]--mergeOrd [] ys = ys-mergeOrd xs [] = xs-mergeOrd (x:xs) (y:ys)-  | x<y        = x : mergeOrd xs (y:ys)-  | x==y       = x:y: mergeOrd xs ys-  | otherwise  = y : mergeOrd (x:xs) ys------- Solution 15.9------- change the line---          | x==y       = x:y: mergeOrd xs ys--- to---          | x==y       = x: mergeOrd xs ys------- Solution 15.10------- assuming that x `f` y iff x<=y.--mergeSort' :: (a -> a -> Bool) -> [a] -> [a]--mergeSort' _ [] = []--mergeSort' _ [x] = [x]--mergeSort' f xs -  = mergeOrd' f (mergeSort' f left) (mergeSort' f right) -    where-    (left,right) = splitAt (length xs `div` 2) xs--mergeOrd' ::  (a -> a -> Bool) -> [a] -> [a] -> [a]--mergeOrd' _ [] ys = ys-mergeOrd' _ xs [] = xs-mergeOrd' f (x:xs) (y:ys)-  | x `f` y        = x : mergeOrd' f xs (y:ys)-  | otherwise      = y : mergeOrd' f (x:xs) ys------- Solution 15.11------- already in MakeTree.hs------- Solution 15.12------- Stadard calculation.------- Solution 15.13------- showTable is a standard layout problem.--showTree :: Tree -> String--showTreeInd :: Int -> Tree -> String--showTree = showTreeInd 0--showTreeInd n (Leaf ch int) = replicate n ' ' ++ show ch ++ ": " ++ show int ++"\n"-showTreeInd n (Node m t1 t2) = showTreeInd (n+4) t1 ++-                               replicate n ' ' ++ show n ++-                               showTreeInd (n+4) t2------- Solution 15.14------- Basic property to expect is that (decode.code) is the identity function, or---       decode (code string) = string--- But need the string to come from the elements in the code tree. Alternatively--- can just left the coding function drop anything unrecodgnised, and then compare--- the results of decode.code with the string with the unrecognised characters --- removed. This means don't have to write a special generator, but means that most--- of the tests are effectively on the empty list.------- Solution 15.15-----sorted :: [Int] -> Bool--sorted [] = True-sorted [x] = True-sorted (x:y:zs) = x<=y && sorted (y:zs)------- Solution 15.16------- Pretty open-ended. Note discussion for 15.14 above. Often different ways of--- solving the same problem.------- Solution 15.17------- an example is given in 15.14.------- Solution 15.18------- It's possible to write a property / test of whether a sequence of L's and R's is--- a valid code. For the abt tress above, would have LL as a valid code sequence but--- not LR, as this should be LRL or LRR. Any sequence is a valid initial segment, so --- can be extended to a valid code. Once that's done, then should expect that--- code.decode is also the identity (on that subset).----------
− Chapter15/Test.hs
@@ -1,34 +0,0 @@--------------------------------------------------------------------------------         Test.hs------ 	The test module of the Huffman example------ 	(c) Addison-Wesley, 1996-2011.-------------------------------------------------------------------------------module Test where---- The test module of the Huffman example--import Main-import Test.QuickCheck-import Data.List ( nub )----- QuickCheck testing--checkInverse :: String -> Bool--checkInverse string = -    decodeMessage tree (codeMessage table string) == string-        where-          tree = codes string-          table = codeTable tree---- prop_Hufmann :: String -> Bool--prop_Hufmann string =-    (length (nub string) > 1) ==> checkInverse string-    
− Chapter16/Solutions16.hs
@@ -1,474 +0,0 @@------------------------------------------------------------------------------------- 	Haskell: The Craft of Functional Programming--- 	Simon Thompson--- 	(c) Addison-Wesley, 2011.--- --- 	Solutions16------------------------------------------------------------------------------------module Solutions16 where--import Tree-import UseTree---- The type Var.--type Var = Char------- Solution 16.1------- The implementation here has names suffixed with "S"--type StoreS = [(Var, Integer)]--initialS :: StoreS--initialS = []---- Note that in case the variable isn't bound, returns 0.--valueS :: StoreS -> Var -> Integer--valueS [] v = 0 --valueS ((w,n):sto) v-  | w<v            = valueS sto v-  | w==v           = n-  | otherwise      = 0---- This implementation overwrites the previous binding (assumed--- to be unique).--updateS :: StoreS -> Var -> Integer -> StoreS--updateS [] v n = [(v,n)]--updateS ((w,m):sto) v n-  | w<v         = (w,m) : updateS sto v n-  | w==v        = (v,n) : sto-  | otherwise   = (v,n) : (w,m) : sto------- Solution 16.2------- For the implemetation in 16.1 it's actual equality. For the non---- ordered implementation in the chapter, need only to look at the first --- values given to variables: variable,value pairs later in the list are--- ignored.---- For function types need some indication of what the domain is. The neatest--- way to do this is to pair the function with a list of variables which --- gives the set of variables defined. Need just to check equalities on these--- lists.------- Solution 16.3------- Using a maybe type we can avoid returning the conventional 0 when a--- variable isn't defined. Instead say this, modifying the solution to--- 16.1.--valueS' :: StoreS -> Var -> Maybe Integer--valueS' [] _ = Nothing --valueS' ((w,n):sto) v-  | w<v            = valueS' sto v-  | w==v           = Just n-  | otherwise      = Nothing------- Solution 16.4-----hasVal ::  StoreS -> Var -> Bool--hasVal [] _ = False --hasVal ((w,n):sto) v-  | w<v            = hasVal sto v-  | w==v           = True-  | otherwise      = False------- Solution 16.5------- Easy for the functional implementation.---- For the list implementation would have to define a "catch all" variable, or--- ass an extr field to a record which is the default value for variables as--- yet unassigned.------- Solution 16.6------- Need to choose an appropriat esubset of the type signatures of the functions--- in the case study. ---- An important point is not to include in the API functions which can be defined--- in terms of other API functions. If that's the case, define them in this was so--- that if/when the API is redefined these functions don't need to be redefined.------- Solution 16.7------- Standard calculations.------- Solution 16.8------- This exercise helps to make concrete the differences between the three implementations.------- Solution 16.9------- If a queue is not empty, then the the first element to be removed will--- be the same before and after adding another element to the queue.---- If a queue is empty and x is added, then x is the first element in the --- queue.------- Solution 16.10------- Can add elements to either end of the queue and if it is non-empty--- can remove an element from either end too. Could implement with a single--- list, or with a pair of lists: the latter should be much more efficient.---- In both cases it's a matter of extending one of the existing implementations--- with implmentations of the two new operations.------- Solution 16.11------- Same API as the ordinary queue; need to implement so that don't add a new--- entry for a value already in the queue.---- Alternatively could add another operation to the queue to check when an--- entry is already present, so that can know when it's (not) worth adding--- an entry. ------- Solution 16.12-----type Priority = Int---- Store elements in descending order of priority. Within a particular priority --- store in FIFO form.---- Note that this is a "concrete" implementation. If it's to be an ADT then--- need to declare as a newtype with a wrapping constructor.--type PriQ a = [(Int,[a])]--emptyPQ = []--isEmptyPQ [] = True-isEmptyPQ _  = False--addPQ :: a -> Priority -> PriQ a -> PriQ a--addPQ x p [] = [(p,[x])]-addPQ x p qs@((q,ys):rest)-  | p>q         = (p,[x]):qs-  | p==q        = (q,ys++[x]):rest-  | p<q         = (q,ys) : addPQ x p rest--remPQ :: PriQ a -> (Maybe a, PriQ a)--remPQ q-  | isEmptyPQ q   = (Nothing, q)-  | otherwise     = (Nothing, [])------- Solution 16.13------- Once accumulated the scores of each letter can put into a priority queue; this--- could help in tree building.------- Solution 16.14------- Can define isNil from isNode, and vice versa---- Can define isNil from minTree: it will return Nothing iff tree is Nil.---- Given any (finite) tree value t where elements are in Ord a can define nil thus:--{--makeNil :: Ord a => Tree a -> Tree a-makeNil t-  | res == Nothing      = t-  | otherwise           = makeNil (delete min t)-    where-    res = minTree t-    Just min = res--}------- Solution 16.15------- Depends a bit on what the database is to do, but need lookups and updates, as--- well as initial value. Can define e.g. number of loans from the interface functions.------- Solution 16.16------- Two sorts of interface here---- Using an existing index: take word to page range. Take page to all entries, perhaps?---- Building an index: take a text to an index.------- Solution 16.17------- QueueState:--- can define queueEmpty from queueLength---- ServerState:--- can define simulationStep using serverStep, shortestQueue and addToQueue--- is it enough to have simulationStep, serverStart and serverSize? certainly--- it is to actually run the simulation step by step.------- Solution 16.18------- In the light of the previous answer, it would be enough to include--- simulationStep, serverStart and serverSize in an interface, and to have--- the "next queue" as an element of the state, but not directly accessible--- from the interface:---- type NextState      = Int--- newtype ServerState = SS ([QueueState],NextState)---- Alternatively if more is to be exposed, then need a function to reveal--- the current value of the "next state------- Solutions 16.19,20------- Standard calculations.------- Solution 16.21------- QueueState: running the queue to completion on a list of n inputs--- should produce a list of n outputs, processed in order in which they --- arrived. In order to do this need to define a number of auxiliary --- functions, the major one being a funciton to run the queue to --- completion on an input list.---- Need to take account here of the arrival times: can't expect to --- process something (at least) until it has arrived. Halt processing when--- there are no more input messages to process and the queue itself is--- empty.------- Solution 16.22------- Need to know how many queues there are, and can't tell this from an --- arbitrary function of type (Int -> QueueState); need to pair this function--- with an Int telling you the number of queues. Once that's there, replace --- accessing a queue by list indexing and instead just use function application.--- e.g. in the definition of addToQueue don't have to split the list up,--- operate on one element and then form another list; instead simply change the --- value of the function on argument n.------- Solution 16.23------- See solution 16.17 above.------- Solutions 16.24-25------- See solution 16.18 above.------- Solution 16.26------- A different version of the round robin implemetation --- will keep a, ordered list of (Int,Queue) pairs and ensure that--- the current/next queue is always at the head.------- Solution 16.27,28------- There are two approaches here: could test the accessor, selector--- and discriminator functions, but we should be able to assume these--- are ok. Here we test for the top level properties of how elementhood--- interacts with insertion and deletion:--prop_add_tree :: Int -> Int -> Tree Int -> Bool--prop_add_tree n m t-  = elemT n t == elemT n (insTree m t) || n==m--prop_delete_tree :: Int -> Int -> Tree Int -> Bool--prop_delete_tree n m t-  = elemT n t == elemT n (delete m t) || n==m---- Could also check that the minTree function indeed picks the minimum--- value in the tree by comparing it with the nth value in the tree:--prop_min_tree :: Integer -> Tree Int -> Bool--prop_min_tree i t-  = let Just min = minTree t in-        min <= indexT i t || isNil t -- || "i not valid"---- would be easier for this to be defined if indexT returned a Maybe a--- indicating whether or not the index is in range: exercise.------- Solution 16.29-----{--successor :: Ord a => a -> Tree a -> Maybe a--successor v Nil = Nothing-successor v (Node x t1 t2)-  | x<=v          = successor v t2-  | otherwise     = case maxT t1 of-                      Nothing -> x-                      Just y  -> if y>v -                                    then successor v t1-                                    else x--maxT :: Ord a => Tree a -> Maybe a--maxT Nil            = Nothing-maxT (Node x _ Nil) = Just x-maxT (Node x _ t2)  = maxT t2--}------- Solution 16.30------- Stree is defined on p398.---- The paradigm for the solution is given on p398--- where it is shown that the new field gives the value it--- should, while the other functions need to maintain that--- value.------- Solution 16.31------- Built on the model of Stree: need to make sure that the --- functions manipulate the "cached" values appropriately.---- This is not caching the size, incidentally.--data MMtree a = NilMM | NodeMM a a a (MMtree a) (MMtree a)--insTreeMM :: Ord a => a -> MMtree a -> MMtree a--insTreeMM val NilMM = NodeMM val val val NilMM NilMM--insTreeMM val (NodeMM x minV maxV t1 t2)-  | val<=x          = NodeMM x newMin maxV newT1 t2-  | val>x           = NodeMM x minV newMax t1 newT2-    where-    newMin      = min val minV-    newMax      = max val maxV-    newT1       = insTreeMM val t1-    newT2       = insTreeMM val t2 ---- Note that because of lazy evaluation (Chapter 17) in each--- case will only compute one of newMin / newMax and newT1 / newT2--- according to the relation between val and x, the value at the--- root of the tree.------- Solution 16.32------- The implentation type could remain the same, but it would be better to --- store an occurrence count with each element (with the assumption --- that no element occurs more than once). ---- If the implementation type remains the same, then need to scan for all--- occurrences of a particular element when looking for its occurrence --- count.---- Should extend the interface with an element occurrence function, rather--- than simply checking elementhood. This effectively gives "bags" rather--- than "sets".------- Solution 16.33------- Search trees keep the implementation ordered. This is a straightforward --- re-implementation of the application.------- Solution 16.34------- This solution takes a different approach. Update the b value by passing in--- an update function, of type (b -> b), to the insertion. This is applied to, e.g.--- add an instance of a word to a list of instances, so might be (++[newOccurrence])--- in that case.--data GenTree a b = GenNil b-                 | GenNode a b (GenTree a b) (GenTree a b)--insertGenTree :: Ord a => a -> (b -> b) -> GenTree a b -> GenTree a b--insertGenTree x f (GenNil b)-  = GenNode x (f b) (GenNil b) (GenNil b)--insertGenTree x f (GenNode a b t1 t2)-  | x==a          = GenNode a (f b) t1 t2-  | x<a           = GenNode a b (insertGenTree x f t1) t2-  | x>a           = GenNode a b t1 (insertGenTree x f t2)------- Solution 16.35------- One gives a total ordering, but of less value than a (partial) subset ordering.------- Solutions 16.36 - 16.44 SEE SolutionsSet.hs---------- Solutions 16.45 - 16.50 SEE SolutionsRelation.hs-----
− Chapter16/Store.hs
@@ -1,48 +0,0 @@-----------------------------------------------------------------------------  --- 	   Store.hs---  ---         An abstract data type of stores of integers, implemented as---         a list of pairs of variables and values.			--- 									---         (c) Addison-Wesley, 1996-2011.					---  ----------------------------------------------------------------------------module Store -   ( Store, -     initial,     -- Store-     value,       -- Store -> Var -> Integer-     update       -- Store -> Var -> Integer -> Store-    ) where---- Var is the type of variables.					--type Var = Char---- The implementation is given by a newtype declaration, with one--- constructor, taking an argument of type [ (Integer,Var) ].--data Store = Store [ (Integer,Var) ] --instance Eq Store where -  (Store sto1) == (Store sto2) = (sto1 == sto2)					--instance Show Store where-  showsPrec n (Store sto) = showsPrec n sto					---  -initial :: Store --initial = Store []--value  :: Store -> Var -> Integer--value (Store []) v         = 0-value (Store ((n,w):sto)) v -  | v==w            = n-  | otherwise       = value (Store sto) v--update  :: Store -> Var -> Integer -> Store--update (Store sto) v n = Store ((n,v):sto)-
+ Chapter19/.DS_Store view

binary file changed (absent → 6148 bytes)

+ Chapter19/._.DS_Store view

binary file changed (absent → 82 bytes)

+ Chapter19/ParseLib.hs view
@@ -0,0 +1,132 @@+-------------------------------------------------------------------------+-- +-- 	Haskell: The Craft of Functional Programming, 3e+-- 	Simon Thompson+-- 	(c) Addison-Wesley, 1996-2011.+-- +-- 	ParseLib.hs+-- +-- 	Library functions for parsing	+--      Note that this is not a monadic approach to parsing.	+-- +---------------------------------------------------------------------------                                                                                                  ++module ParseLib where++import Data.Char++infixr 5 >*>+--   +-- The type of parsers.						+--  +type Parse a b = [a] -> [(b,[a])]+--  +-- Some basic parsers						+--  +--  +-- Fail on any input.						+--  +none :: Parse a b+none inp = []+--  +-- Succeed, returning the value supplied.				+--  +succeed :: b -> Parse a b +succeed val inp = [(val,inp)]+--  +-- token t recognises t as the first value in the input.		+--  +token :: Eq a => a -> Parse a a+token t (x:xs) +  | t==x 	= [(t,xs)]+  | otherwise 	= []+token t []    = []+--  +-- spot whether an element with a particular property is the 	+-- first element of input.						+--  +spot :: (a -> Bool) -> Parse a a+spot p (x:xs) +  | p x 	= [(x,xs)]+  | otherwise 	= []+spot p []    = []+--  +-- Examples.							+--  +bracket = token '('+dig     =  spot isDigit++-- Succeeds with value given when the input is empty.++endOfInput :: b -> Parse a b+endOfInput x [] = [(x,[])]+endOfInput x _  = []+--  +-- Combining parsers						+--  +--  +-- alt p1 p2 recognises anything recogniseed by p1 or by p2.	+--  +alt :: Parse a b -> Parse a b -> Parse a b+alt p1 p2 inp = p1 inp ++ p2 inp+exam1 = (bracket `alt` dig) "234" +--  +-- Apply one parser then the second to the result(s) of the first.	+--  ++(>*>) :: Parse a b -> Parse a c -> Parse a (b,c)+-- 	+(>*>) p1 p2 inp +  = [((y,z),rem2) | (y,rem1) <- p1 inp , (z,rem2)  <- p2 rem1 ]+--  +-- Transform the results of the parses according to the function.	+--  +build :: Parse a b -> (b -> c) -> Parse a c+build p f inp = [ (f x,rem) | (x,rem) <- p inp ]+--  +-- Recognise a list of objects.					+--  +-- 	+list :: Parse a b -> Parse a [b]+list p = (succeed []) +         `alt`+         ((p >*> list p) `build` convert)+         where+         convert = uncurry (:)+--  +-- Some variants...++-- A non-empty list of objects.						+--  +neList   :: Parse a b -> Parse a [b]+neList p = (p  `build` (:[]))+           `alt`+           ((p >*> list p) `build` (uncurry (:)))++-- Zero or one object.++optional :: Parse a b -> Parse a [b]+optional p = (succeed []) +             `alt`  +             (p  `build` (:[]))++-- A given number of objects.++nTimes :: Int -> Parse a b -> Parse a [b]+nTimes 0 p     = succeed []+nTimes (n+1) p = (p >*> nTimes n p) `build` (uncurry (:))+--  +-- Monadic parsing++data SParse a b = SParse (Parse a b)++instance Monad (SParse a) where+  return x = SParse (succeed x)+  (SParse pr) >>= f +    = SParse (\st -> concat [ sparse (f a) rest | (a,rest) <- pr st ])++sparse :: SParse a b -> Parse a b++sparse (SParse pr) = pr++
− Chapter19/Solutions19.hs
@@ -1,227 +0,0 @@------------------------------------------------------------------------------------- 	Haskell: The Craft of Functional Programming--- 	Simon Thompson--- 	(c) Addison-Wesley, 2011.--- --- 	Solutions19------------------------------------------------------------------------------------module Solutions19 where--import RegExp -import ParseLib-import Data.Char (isLower)-import Test.QuickCheck-import QC-import QCfuns------- Solution 19.1-----interp :: RE -> RegExp--interp Eps         = epsilon-interp (Ch ch)     = char ch-interp (e1 :|: e2) = interp e1 ||| interp e2-interp (e1 :*: e2) = interp e1 <*> interp e2-interp (St e)      = star (interp e)-interp (Plus e)    = i <*> star i-                     where-                     i = interp e------- Solution 19.2------- First pretty printing, which shows the grammar used.--- 'e' is the syntax for epsilon, here.--prettyRE :: RE -> String--prettyRE Eps         = "e"-prettyRE (Ch ch)     = [ch]-prettyRE (e1 :|: e2) = "("++ prettyRE e1 ++"|"++ prettyRE e2 ++ ")"-prettyRE (e1 :*: e2) = "("++ prettyRE e1 ++ prettyRE e2 ++ ")"-prettyRE (St e)      = "("++ prettyRE e ++ ")*"-prettyRE (Plus e)    = "("++ prettyRE e ++ ")+"---- Little parsers--epsP, charP :: Parse Char RE--epsP = spot (=='e') `build` const Eps--charP = spot isLowerNoE `build` Ch--isLowerNoE ch = isLower ch && ch/='e'--altP :: Parse Char RE -> Parse Char RE -> Parse Char RE--altP p1 p2-  = (spot (=='(') >*>-     p1 >*>-     spot (=='|') >*>-     p2 >*>-     spot (==')'))-    `build`-    \ (_,(e1,(_,(e2,_)))) -> e1 :|: e2--seqP :: Parse Char RE -> Parse Char RE -> Parse Char RE--seqP p1 p2-  = (spot (=='(') >*>-     p1 >*>-     p2 >*>-     spot (==')'))-    `build`-    \ (_,(e1,(e2,_))) -> e1 :*: e2---starP :: Parse Char RE -> Parse Char RE--starP p-  = (spot (=='(') >*>-     p >*>-     spot (==')') >*>-     spot (=='*'))-    `build`-    \ (_,(e,(_,_))) -> St e---- pulling them together--reP :: Parse Char RE--reP = epsP -       `alt`-       charP-       `alt`-       altP reP reP-       `alt`-       seqP reP reP-       `alt`-       starP reP-        --- top-level function.--parseRE :: String -> RE--parseRE st-  = e-    where-    [(e,"")] = reP st---- Expected property: the two functions are inverses of each other, when applied to legal --- representations of strings.---- To test in QuickCheck, note that it's difficult to generate legal strings directly,--- instead best to generarte REs and turn them into legal strings.------- Solution 19.3-----palin :: RE --palin = (middle :|: (a :*: (palin :*: a))) :|: (b :*: (palin :*: b))--middle = (Eps :|: (a :|: b))------- Solution 19.4------- Just follow the pattern of recursion used in the definition of reP above.--- Works just like 19.3.------- Solution 19.5------- I believe that "recursive regular expressions" = "context free grammars" and--- so this set of strings will therefore not be representable.------- Solution 19.6------- What does extension mean? Add a construct to RE and then extend its--- interpretations into RegExp, enumeration, concrete syntax etc.---- MatchN Int RE, interpreted by--matchN :: Int -> RegExp -> RegExp--matchN n re-  | n<=0        = epsilon-  | otherwise   = re <*> matchN (n-1) re----- Ranges etc. are all pretty straightforward.------- Solution 19.7-------- Actually not so difficult to implement ...--matchBoth :: RegExp -> RegExp -> RegExp--matchBoth re1 re2 st -  = re1 st && re2 st--matchNot :: RegExp -> RegExp--matchNot re st-  = not (re st)------- Solutions 19.8-10------- See the module PositionedImages.hs------- Solution 19.11------- This was discussed in Solutions12,  question 12.19.------- Solution 19.12-----samplePretty :: IO ()--samplePretty-  = do exprs <- sample' (arbitrary :: Gen Expr)-       printLines (map ((++"\n").prettyE) exprs)--printLines :: [String] -> IO ()--printLines strs-  = if strs == [] -       then return ()-       else do putStr (head strs)-               printLines (tail strs)------- Solution 19.13------- Generators standard.---- Properties ---   - should be able to round trip exp -> pretty -> exp---   - not so obvious how to test the fact that the evaluator gives---     the right result.---   - one idea is to build pairs of expression and their values, which---     are generated simultaneously ,,, of course, that is tantamount ---     to defining a second evaluation function (albeit implicitly).------- Solution 19.14------- Five finger exercise ...
Craft3e.cabal view
@@ -1,6 +1,6 @@  name: Craft3e-version: 0.1.0.5+version: 0.1.0.6 license: MIT license-file: LICENSE copyright: (c) Addison Wesley