Is the order in which we call bracket and handle important?
Yup, it is pretty important: the code executed during the in-between statement of bracket still can raise an exception. We do not want our application to crash in case of an error while opening the file, therefore, we still need the handle statement.
We could put the handle statement inside of the bracket statement, but since no exception would be thrown, we would risk to leak some resources.
How could we traverse the directory three in reverse alphabetic order?
Well, it is quite straightforward, before iterating on directories, we apply the order function on the list containing them. Therefore, we only need to apply reverse as the order function.
ControllerVisit> ControllerVisit.traverse reverse "/home/minoulefou/test"
Implement an order function which traverses the tree in postorder.
For each file info type handled by the
order function, we have two options:
- The file is a directory: we want to first handle its children then handle the directory.
- The file is not a directory: we will apply the identity function to this file.
I implemented this recursive function as follows:
postOrder :: [Info] -> [Info] postOrder (x:xs) = if isDirectory x then postOrder xs ++ [x] else x:postOrder xs postOrder  = 
As you can see, it the implementation is quite straightforward.
There may be some other ones, do not hesitate to shout me out if you found something else.
We want to adapt previously implemented predicates with the new
First we need to express InfoP using info:
type InfoP a = Info -> a
We will now implement predicates equality and comparaison: we’ll need to reimplement liftP with the new InfoP type:
liftP :: (a -> b -> c) -> InfoP a -> b -> InfoP c liftP op infoP test info = infoP info `op` test
Once we implemented this function, implementing equality and inequity predicates is trivial:
greaterP, lesserP :: (Ord a) => InfoP a -> a -> InfoP Bool greaterP = liftP (>) lesserP = liftP (<) equalsP :: (Eq a) => InfoP a -> a -> InfoP Bool equalsP = liftP (==)
Once again, in order to implement combinators, we’ll use another lift function.
liftP2 :: (a -> b -> c) -> InfoP a -> InfoP b -> InfoP c liftP2 op pred1 pred2 info = pred1 info `op` pred2 info andP, orP :: InfoP Bool -> InfoP Bool -> InfoP Bool andP = liftP2 (&&) orP = liftP2 (||)
As for the previous question, we’ll use some infix notations for each operation: it is more handy to use.
(==?)::(Eq a) => InfoP a -> a -> InfoP Bool (==?) = equalsP (>?), (<?) :: (Ord a) => InfoP a -> a -> InfoP Bool (>?) = greaterP (<?) = lesserP (&&?),(||?):: InfoP Bool -> InfoP Bool -> InfoP Bool (&&?) = andP (||?) = orP
Write a wrapper for
traverse that lets you control traversal using one
predicate and filter results using another.
Here, we want to add a behaviour to the ord function. Not only we want that function to order the results, be we also want it to filter them. An easy approach to this problem seems to be composing the filter function with the order function:
traverse' order pred path = ControllerVisit.traverse (order . filter pred) path
Exercise P. 232
Modify foldtree to allow the caller to change the order of traversal of entries in a directory.
First, we need to specify the new fold function signature:
foldTree' ::([FilePath] -> [FilePath]) -> Iterator a -> a -> FilePath -> IO a foldTree' order iter initSeed path = ...
We will plug this function to the existing foldTree on the fold subfunction as follow:
fold seed subpath = do paths <- getUsefulContent subpath walk seed $ order paths
The remaining code will still unchanged.
Aaaand, the two remaining exercises are quite similar to the previous ones, I will pass on that :)
See you soon for chapter 10 solutions!