In Programming in Haskell, Graham Hutton defines an unfold for lists as follows:
unfold :: (b -> Bool ) -> (b -> a) -> (b -> b) -> b -> [a]
unfold p h t x | p x = []
| otherwise = h x : unfold p h t (t x)
Define a function
• listUnfold :: (b -> Bool) -> (b -> a) -> (b -> b) -> b -> [a]
that is similar to the one above but uses unfoldr in its implementation and is non-recursive.
I've been trying for a while to solve the question above but I still can manage to do so (pretty new in Haskell and functional programming in general).
My attempt:
listUnfold :: (b -> Bool) -> (b -> a) -> (b -> b) -> b -> [a]
listUnfold f h t x
| f x == True = []
| otherwise = h x :
listUnfoldr (\x -> if f x then Nothing else Just ((h x), (t x))) x
In english, if f x
is true, return the empty list. Otherwise, use h x
as the head and append the results of unfoldr as the tail. Unfoldr takes a list (x:xs)
should recurse itself with x
as the head and xs
as the tail.
p/s: I'm probably doing this very very wrongly.
You've almost got it! The original function uses the function p
(for 'predicate') to determine whether we've finished unfolding, h
to apply to each element, and t
(for 'transformation') to transform an element into the seed for the rest of the list.
unfoldr
expects a single function f :: b -> Maybe (a,b)
, which returns Nothing
if we've finished unfolding, or Just (x, y)
, where x
is the element to add to the list and y
is the seed for the rest of the list.
So f
in unfoldr
is responsible for the functionality of all three of p
, h
and t
. The Nothing
-or-Just
dichotomy plays the part of the Boolean function p
, and the second element of the tuple does t
's job of supplying the seed for the rest of the list.
Here's my solution (I've renamed the variables from your question, for clarity):
listUnfold pred f trans seed =
unfoldr (\x -> if pred x
then Nothing
else Just (f x, trans x)) seed
Of course, when a value appears on the right-hand-end of a definition, as seed
does here, you can take advantage of Haskell's sexy syntax for currying and throw it away altogether:
listUnfold pred f trans = unfoldr (\x -> if pred x
then Nothing
else Just (f x, trans x))
Formally, this transformation is known as eta reduction.