This is a question on a usage issue with Data.List.Class (related to a previous question on Haskell Data.List.Class and syntax).
Relevant segments of the code are listed below. From my understanding, this class is providing a type class interface or generalization to the Haskell list type, which could be really useful. However, I couldn't really find much documentation out there on the usage of this class. Does any one know a good tutorial?
Also, I have a technical/specific question regarding its usage and types. From the code, I would think that in the type class definition, runList and joinL are inverses of each other (in a certain sense).
-- other stuff omitted
import Data.Functor.Identity (Identity(..))
data ListItem l a =
Nil |
Cons { headL :: a, tailL :: l a }
Data.List.Class
-- | A class for list types. Every list has an underlying monad.
class (MonadPlus l, Monad (ItemM l)) => List l where
type ItemM l :: * -> *
runList :: l a -> ItemM l (ListItem l a)
joinL :: ItemM l (l a) -> l a
cons :: a -> l a -> l a
cons = mplus . return
instance List [] where
type ItemM [] = Identity
runList [] = Identity Nil
runList (x:xs) = Identity $ Cons x xs
joinL = runIdentity
cons = (:)
fromList :: List l => [a] -> l a
fromList = foldr cons mzero
First, I entered joinL $ runList [1, 2, 3] in emacs mode, but I got the following error:
Couldn't match type `ItemM (ListItem [])' with `Identity'
Expected type: ItemM (ListItem []) (ListItem [] Integer)
Actual type: ItemM [] (ListItem [] Integer)
As it says, the expected and actual types do not match exactly. But I can't see why they should require different types in the first place. How are runList :: l a -> ItemM l (ListItem l a) and joinL :: ItemM l (l a) -> l a different in terms of their meaning or semantics?
Also, I tried a very simple function fromList in emacs mode as follows: fromList [1,2,3], yet I got:
Ambiguous type variable `l0' in the constraint:
(List l0) arising from a use of `fromList'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: fromList [1, 2, 3]
In an equation for `it': it = fromList [1, 2, 3]
I am confused here why there is an ambiguity here, and how to add a type signature as the error message prompts. Anyone can help explain it?
Thanks in advance,
For last question: it may be several types that implements List typeclass, you should specify it if it will not be inferenced later. For example fromList [1, 2, 3] :: [Int] works fine.
Related
So i am in need of a function which takes two lists, x and y and output a list of elements that are in List x BUT NOT IN List y.
ie. the output should look something like is
*Main> filterVars ["a","c","h","d"] ["c","b","a"]
["h","d"]
I want to use the filter function in Haskell to practice. My code is below;
filterVars :: [a] -> [a] -> [a]
filterVars = filter IsInList (y:ys)
where
IsiIList (x:xs) (y:ys) :: [a] -> [a] -> Bool
IsInList [] _ = []
IsiInList(x:xs) (y:ys)
| elem (x (y:ys)) = IsiInList (xs (y:ys))
| otherwise = x : IsiInList (xs (y:ys))
however I get the following error;
Invalid type signature: IsInList (x : xs) (y : ys) :: ...
Should be of form <variable> :: <type>
| IsInList (x:xs) (y:ys) :: [a] -> [a] -> Bool
My logic is as follows:
When the function filterVars is called with arguments (x:xs) (y:ys), it checks to see the filter criteria IsInList.
The function providing the filtering criteria, IsInList, takes both the arguments (x:xs) and (y:ys). if the first element of the list (x:xs) is an elements of (y:ys), then discard and move to the next element in the x list.
For the case that an element of (x:xs) IS NOT IN list (y:ys), store this value and move onto the next element of the list x until list x is completely parsed through.
return the list containing elements of list x that are not in list y
My confusion arises from my lack of experience with Haskell. Firstly the function filterVars must require two lists and output a list. However when i am defining the function, I use the filter function and the list y as arguments. I know filter outputs a list so i just wanted to know if my initial setup is correct (also would like to gain an insight to the flow of execution in Haskell)
Secondly I am not sure as to what the error means and how to resolve it. Does my logic make sense? Can this be done using lists or am i way of mark?
Your code has a few syntactic and semantic errors. I’ll explain the syntax issues and then get into the semantics of your solution.
In Haskell, the names of functions, variables, and type variables must begin with a lowercase letter; capitalised names refer to types, data constructors, or modules. Therefore you need to rename IsInList to isInList, and fix the name typos.
A where clause on a definition is followed by a block of variable bindings (pattern = expression). A block may be delimited by curly braces with items separated by semicolons ({ … ; … ; … }) but it’s more common to use indentation-based layout. Therefore you need to indent the contents of the where block. A simple rule is to put a newline + indent (with spaces) after any layout keyword—where, do, of, or let—whenever you have a multi-line block.
The type signature of a function is written as name :: type, but you’ve written what looks like a pattern on the left-hand side in isInList (x:xs) (y:ys) :: [a] -> [a] -> Bool. If you want to include a type signature here, you should write isInList :: [a] -> [a] -> Bool. However, I’m going to just remove the signature, for reasons I’ll explain below.
With those fixes, your code looks like this:
filterVars :: [a] -> [a] -> [a]
filterVars = filter isInList (y:ys)
where
isInList [] _ = []
isInList (x:xs) (y:ys)
| elem (x (y:ys)) = isInList (xs (y:ys))
| otherwise = x : isInList (xs (y:ys))
Here’s my reading of this code:
filterVars is equal to calling filter with two arguments, isInList and y : ys. y and ys are not in scope here, since you haven’t added them as parameters or pattern variables in the definition of filterVars.
isInList takes two arguments; if the first is an empty list, it returns an empty list. This is not quite right, since filter has the type (a -> Bool) -> [a] -> [a], that is, its first argument should be a function which tests an element of the filtered list and returns a Bool to indicate whether it should be included in the result.
If isInList is given two non-empty lists, then this is followed by a guard to decide which case to proceed to. You’re trying to use the elem function to test whether x is in the list y : ys as the condition here, but the way you call it, you’re passing y : ys as an argument to x, as if it were a function, and then calling elem on the result of that. If you want to pass two arguments to a function, you just separate them with spaces, and include parentheses if necessary for grouping, e.g.: elem x (y : ys). You have the same issue with both calls to isInList (xs (y:ys)), when you probably intended isInList xs (y:ys).
At this point it’s clear to me that you’re mixing up two things: filtering a list using filter, and filtering it by writing a recursive function.
If you want to write this using filter, you should begin with the problem statement: “a function which takes two lists, x and y and output[s] a list of elements that are in List x BUT NOT IN List y”. You want to write a function that takes two parameters, x and y, and filters x by a function that, given an element of x, returns true if the element is not in y.
This can be transcribed fairly literally:
filterVars :: [a] -> [a] -> [a]
-- Select the elements of ‘x’ not in ‘y’…
filterVars x y = filter notInY x
where
-- …where an element ‘e’ is not in ‘y’ if
-- it’s ‘not’ the case that ‘e’ is an ‘elem’ of ‘y’.
notInY e = not (elem e y)
But this has one issue: this function says it can take a list of values of any type a, and test for their presence in a list using elem, but this isn’t true: we could supply a type like Double -> String that’s not comparable at all! In reality, elem is restricted to types that are in the set of types with equality, the Eq typeclass, so we have to add an Eq constraint to the signature to enable the use of elem:
filterVars :: (Eq a) => [a] -> [a] -> [a]
Now, about the local type signature in the where block, the rule in Haskell is that if you write a polymorphic type signature with type variables (typically single letters like a, b, f, m…) then those variables are local to that type signature. So if you write this:
filterVars :: (Eq a) => [a] -> [a] -> [a]
filterVars x y = filter notInY x
where
notInY :: a -> Bool
notInY e = not (elem e y)
That’s equivalent to this:
filterVars :: (Eq a1) => [a1] -> [a1] -> [a1]
filterVars x y = filter notInY x
where
notInY :: a2 -> Bool
notInY e = not (elem e y)
The a of the notInY signature is different from the a in the filterVars signature, so this would cause a type error. The solution is to remove the local type signature or use the ScopedTypeVariables extension to explicitly define the scope of a:
{-# LANGUAGE ScopedTypeVariables #-}
filterVars :: forall a. (Eq a) => [a] -> [a] -> [a]
filterVars x y = filter notInY x
where
notInY :: a -> Bool
notInY e = not (elem e y)
The forall introduces an explicit scope for a, so any a in a type signature in this definition refers to the same a. (An explicit forall is just like the <T> syntax in many imperative programming languages to define generic parameters.)
As a matter of style, you can also write this same structure in a few different ways, and you should make sure you understand these:
filterVars x y = filter (notIn y) x
where
notIn list e = not (elem e list)
filterVars x y = filter (\ e -> not (elem e y)) x
filterVars x y = filter (`notElem` y) x
This is very typical Haskell code, and a good concise solution. But since you’re learning Haskell, you should try to solve this problem with explicit recursion, effectively inlining the definition of filter into your code. For that, you do want to proceed by pattern-matching as you were trying to do in your isInList function. You can start with either of the following structures, using a case expression or multiple function equations, whichever you prefer:
filterVars :: (Eq a) => [a] -> [a] -> [a]
filterVars x y = case x of
[] -> {- 1 -}
e : rest
| {- 2 -} -> {- 3 -}
| otherwise -> {- 4 -}
filterVars :: (Eq a) => [a] -> [a] -> [a]
filterVars [] y = {- 1 -}
filterVars (e : rest) y
| {- 2 -} = {- 3 -}
| otherwise = {- 4 -}
And fill in the following details, marked with {- … -} comments in the code above:
[a]; What do you return when x is empty, i.e., what happens when you call filterVars [] ["c", "b", "a"] directly or as the base case of your recursion?
Bool; When x is non-empty, containing some element e and some (possibly empty) remainder rest, what condition do you use to test whether e is an element of y? (E.g. in filterVars ["a", "d", "b"] ["c", "b", "a"], e is "a" and rest is ["d", "b"].)
[a]; What do you return when e is an element of y? Should you keep or discard the element? What do you do with the rest of the input?
[a]; What do you return when e is not in y? What do you do with the rest of the input then?
Recall that you can always step through Haskell code using equational reasoning, by substituting things on either side of an = sign, since = actually means equal! For example, if your function had a case f [] = [], then whenever you see f [], you can replace it with []; if it had a case f (x : xs) = x + f xs, when you see a call to f [1, 2, 3], this is the same as f (1 : [2, 3]), and likewise f (1 : (2 : (3 : []))), so you can match x = 1 and xs = 2 : (3 : []) and substitute their values in the right-hand side x + f xs → 1 + f [2, 3].
Lets say I have nested lsit: [1, [2, 3, 4], [5, [6]]] and I want to count how many elements it has. In this case it is six elements. I have written such code for doing this:
totalElems :: [a] -> Int
totalElems (x:xs) = case (x, xs) of
(_, []) -> 0
(y:ys, _) -> 1 + totalElems ys + totalElems xs
(_, _) -> 1 + totalElems xs
But I've got an error:
a.hs:4:42:
Couldn't match expected type ‘a’ with actual type ‘[a0]’
‘a’ is a rigid type variable bound by
the type signature for totalElems :: [a] -> Int at a.hs:1:15
Relevant bindings include
xs :: [a] (bound at a.hs:2:15)
x :: a (bound at a.hs:2:13)
totalElems :: [a] -> Int (bound at a.hs:2:1)
In the pattern: y : ys
In the pattern: (y : ys, _)
In a case alternative:
(y : ys, _) -> 1 + totalElems ys + totalElems xs
How I can do this in Haskell?
You can't make freeform lists-within-lists like that in Haskell. Dynamically typed langues will tolerate silliness like that, but strongly-typed Haskell won't.
1 is of type Int, and [2,3,4] is of a different type [Int]. Things in a list have to be of the same type.
However, you could do something like this:
data Nest a = Elem a | List [Nest a]
example ::Nest Int
example = List [Elem 1, List [Elem 2, Elem 3, Elem 4], List [Elem 5, List [Elem 6]]]
countNest :: Nest a -> Int
countNest (Elem x) = 1
countNest (List xs) = sum $ map countNest xs
Let's say I have nested lsit: [1, [2, 3, 4], [5, [6]]]
You can't have that list. It won't type-check. Try typing it by itself in GHCi; it'll just spit an error message at you. Since this input can't exist in the first place, trying to write a function to process it is a doomed endeavor.
Instead, you need to define a custom data type for this. See the other answers.
As others have said, the simplest way to do this is with a different data structure, like the tree NovaDenizen defined. However, just so you know, Haskell's type system enables various ways of creating "lists" in which the elements have different types : see https://wiki.haskell.org/Heterogenous_collections
You don't offen see Maybe List except for error-handling for example, because lists are a bit Maybe themselves: they have their own "Nothing": [] and their own "Just": (:).
I wrote a list type using Maybe and functions to convert standard and to "experimental" lists. toStd . toExp == id.
data List a = List a (Maybe (List a))
deriving (Eq, Show, Read)
toExp [] = Nothing
toExp (x:xs) = Just (List x (toExp xs))
toStd Nothing = []
toStd (Just (List x xs)) = x : (toStd xs)
What do you think about it, as an attempt to reduce repetition, to generalize?
Trees too could be defined using these lists:
type Tree a = List (Tree a, Tree a)
I haven't tested this last piece of code, though.
All ADTs are isomorphic (almost--see end) to some combination of (,),Either,(),(->),Void and Mu where
data Void --using empty data decls or
newtype Void = Void Void
and Mu computes the fixpoint of a functor
newtype Mu f = Mu (f (Mu f))
so for example
data [a] = [] | (a:[a])
is the same as
data [a] = Mu (ListF a)
data ListF a f = End | Pair a f
which itself is isomorphic to
newtype ListF a f = ListF (Either () (a,f))
since
data Maybe a = Nothing | Just a
is isomorphic to
newtype Maybe a = Maybe (Either () a)
you have
newtype ListF a f = ListF (Maybe (a,f))
which can be inlined in the mu to
data List a = List (Maybe (a,List a))
and your definition
data List a = List a (Maybe (List a))
is just the unfolding of the Mu and elimination of the outer Maybe (corresponding to non-empty lists)
and you are done...
a couple of things
Using custom ADTs increases clarity and type safety
This universality is useful: see GHC.Generic
Okay, I said almost isomorphic. It is not exactly, namely
hmm = List (Just undefined)
has no equivalent value in the [a] = [] | (a:[a]) definition of lists. This is because Haskell data types are coinductive, and has been a point of criticism of the lazy evaluation model. You can get around these problems by only using strict sums and products (and call by value functions), and adding a special "Lazy" data constructor
data SPair a b = SPair !a !b
data SEither a b = SLeft !a | SRight !b
data Lazy a = Lazy a --Note, this has no obvious encoding in Pure CBV languages,
--although Laza a = (() -> a) is semantically correct,
--it is strictly less efficient than Haskell's CB-Need
and then all the isomorphisms can be faithfully encoded.
You can define lists in a bunch of ways in Haskell. For example, as functions:
{-# LANGUAGE RankNTypes #-}
newtype List a = List { runList :: forall b. (a -> b -> b) -> b -> b }
nil :: List a
nil = List (\_ z -> z )
cons :: a -> List a -> List a
cons x xs = List (\f z -> f x (runList xs f z))
isNil :: List a -> Bool
isNil xs = runList xs (\x xs -> False) True
head :: List a -> a
head xs = runList xs (\x xs -> x) (error "empty list")
tail :: List a -> List a
tail xs | isNil xs = error "empty list"
tail xs = fst (runList xs go (nil, nil))
where go x (xs, xs') = (xs', cons x xs)
foldr :: (a -> b -> b) -> b -> List a -> b
foldr f z xs = runList xs f z
The trick to this implementation is that lists are being represented as functions that execute a fold over the elements of the list:
fromNative :: [a] -> List a
fromNative xs = List (\f z -> foldr f z xs)
toNative :: List a -> [a]
toNative xs = runList xs (:) []
In any case, what really matters is the contract (or laws) that the type and its operations follow, and the performance of implementation. Basically, any implementation that fulfills the contract will give you correct programs, and faster implementations will give you faster programs.
What is the contract of lists? Well, I'm not going to express it in complete detail, but lists obey statements like these:
head (x:xs) == x
tail (x:xs) == xs
[] == []
[] /= x:xs
If xs == ys and x == y, then x:xs == y:ys
foldr f z [] == z
foldr f z (x:xs) == f x (foldr f z xs)
EDIT: And to tie this to augustss' answer:
newtype ExpList a = ExpList (Maybe (a, ExpList a))
toExpList :: List a -> ExpList a
toExpList xs = runList xs (\x xs -> ExpList (Just (x, xs))) (ExpList Nothing)
foldExpList f z (ExpList Nothing) = z
foldExpList f z (ExpList (Just (head, taill))) = f head (foldExpList f z tail)
fromExpList :: ExpList a -> List a
fromExpList xs = List (\f z -> foldExpList f z xs)
You could define lists in terms of Maybe, but not that way do. Your List type cannot be empty. Or did you intend Maybe (List a) to be the replacement of [a]. This seems bad since it doesn't distinguish the list and maybe types.
This would work
newtype List a = List (Maybe (a, List a))
This has some problems. First using this would be more verbose than usual lists, and second, the domain is not isomorphic to lists since we got a pair in there (which can be undefined; adding an extra level in the domain).
If it's a list, it should be an instance of Functor, right?
instance Functor List
where fmap f (List a as) = List (f a) (mapMaybeList f as)
mapMaybeList :: (a -> b) -> Maybe (List a) -> Maybe (List b)
mapMaybeList f as = fmap (fmap f) as
Here's a problem: you can make List an instance of Functor, but your Maybe List is not: even if Maybe was not already an instance of Functor in its own right, you can't directly make a construction like Maybe . List into an instance of anything (you'd need a wrapper type).
Similarly for other typeclasses.
Having said that, with your formulation you can do this, which you can't do with standard Haskell lists:
instance Comonad List
where extract (List a _) = a
duplicate x # (List _ y) = List x (duplicate y)
A Maybe List still wouldn't be comonadic though.
When I first started using Haskell, I too tried to represent things in existing types as much as I could on the grounds that it's good to avoid redundancy. My current understanding (moving target!) tends to involve more the idea of a multidimensional web of trade-offs. I won't be giving any “answer” here so much as pasting examples and asking “do you see what I mean?” I hope it helps anyway.
Let's have a look at a bit of Darcs code:
data UseCache = YesUseCache | NoUseCache
deriving ( Eq )
data DryRun = YesDryRun | NoDryRun
deriving ( Eq )
data Compression = NoCompression
| GzipCompression
deriving ( Eq )
Did you notice that these three types could all have been Bool's? Why do you think the Darcs hackers decided that they should introduce this sort of redundancy in their code? As another example, here is a piece of code we changed a few years back:
type Slot = Maybe Bool -- OLD code
data Slot = InFirst | InMiddle | InLast -- newer code
Why do you think we decided that the second code was an improvement over the first?
Finally, here is a bit of code from some of my day job stuff. It uses the newtype syntax that augustss mentioned,
newtype Role = Role { fromRole :: Text }
deriving (Eq, Ord)
newtype KmClass = KmClass { fromKmClass :: Text }
deriving (Eq, Ord)
newtype Lemma = Lemma { fromLemma :: Text }
deriving (Eq, Ord)
Here you'll notice that I've done the curious thing of taking a perfectly good Text type and then wrapping it up into three different things. The three things don't have any new features compared to plain old Text. They're just there to be different. To be honest, I'm not entirely sure if it was a good idea for me to do this. I provisionally think it was because I manipulate lots of different bits and pieces of text for lots of reasons, but time will tell.
Can you see what I'm trying to get at?
I have to write a function that flattens a list of lists.
For example flatten [] = [] or flatten [1,2,3,4] = [1,2,3,4] or flatten [[1,2],[3],4,5]] = [1,2,3,4,5]
I'm having trouble with the being able to match the type depending on what is given to the flatten function.
Here's what I have:
data A a = B a | C [a] deriving (Show, Eq, Ord)
flatten::(Show a, Eq a, Ord a)=>A a -> A a
flatten (C []) = (C [])
flatten (C (x:xs) ) = (C flatten x) ++ (C flatten xs)
flatten (B a) = (C [a])
From what I can tell the issue is that the ++ operator is expecting a list for both of its arguments and I'm trying to give it something of type A. I've added the A type so the function can either get a single element or a list of elements.
Does anyone know a different way to do this differently, or explain what I can do to fix the type error?
It's a bit unclear what you are asking for, but flattening a list of list is a standard function called concat in the prelude with type signature [[a]] -> [a].
If you make a data type of nested lists as you have started above, maybe you want to adjust your data type to something like this:
data Lists a = List [a] | ListOfLists [Lists a]
Then you can flatten these to a list;
flatten :: Lists a -> [a]
flatten (List xs) = xs
flatten (ListOfLists xss) = concatMap flatten xss
As a test,
> flatten (ListOfLists [List [1,2],List [3],ListOfLists [List [4],List[5]]])
[1,2,3,4,5]
Firstly, the A type is on the right track but I don't think it's quite correct. You want it to be able to flatten arbitrarily nested lists, so a value of type "A a" should be able to contain values of type "A a":
data A a = B a | C [A a]
Secondly, the type of the function should be slightly different. Instead of returning a value of type "A a", you probably want it to return just a list of a, since by definition the function is always returning a flat list. So the type signature is thus:
flatten :: A a -> [a]
Also note that no typeclass constraints are necessary -- this function is completely generic since it does not look at the list's elements at all.
Here's my implementation:
flatten (B a) = [a]
flatten (C []) = []
flatten (C (x:xs)) = flatten x ++ flatten (C xs)
this one liner will do the job. Although as it was mentioned by Malin the type signature is different:
flatten :: [[a]] -> [a]
flatten xs = (\z n -> foldr (\x y -> foldr z y x) n xs) (:) []
simple test
frege> li = [[3,4,2],[1,9,9],[5,8]]
frege> flatten li
[3,4,2,1,9,9,5,8]
Flatten via list comprehension.
flatten arr = [y | x<- arr, y <- x]
I'm trying to write a function that takes a predicate f and a list and returns a list consisting of all items that satisfy f with preserved order. The trick is to do this using only higher order functions (HoF), no recursion, no comprehensions, and of course no filter.
You can express filter in terms of foldr:
filter p = foldr (\x xs-> if p x then x:xs else xs) []
I think you can use map this way:
filter' :: (a -> Bool) -> [a] -> [a]
filter' p xs = concat (map (\x -> if (p x) then [x] else []) xs)
You see? Convert the list in a list of lists, where if the element you want doesn't pass p, it turns to an empty list
filter' (> 1) [1 , 2, 3 ] would be: concat [ [], [2], [3]] = [2,3]
In prelude there is concatMap that makes the code simplier :P
the code should look like:
filter' :: (a -> Bool) -> [a] -> [a]
filter' p xs = concatMap (\x -> if (p x) then [x] else []) xs
using foldr, as suggested by sclv, can be done with something like this:
filter'' :: (a -> Bool) -> [a] -> [a]
filter'' p xs = foldr (\x y -> if p x then (x:y) else y) [] xs
You're obviously doing this to learn, so let me show you something cool. First up, to refresh our minds, the type of filter is:
filter :: (a -> Bool) -> [a] -> [a]
The interesting part of this is the last bit [a] -> [a]. It breaks down one list and it builds up a new list.
Recursive patterns are so common in Haskell (and other functional languages) that people have come up with names for some of these patterns. The simplest are the catamorphism and it's dual the anamorphism. I'll show you how this relates to your immediate problem at the end.
Fixed points
Prerequisite knowledge FTW!
What is the type of Nothing? Firing up GHCI, it says Nothing :: Maybe a and I wouldn't disagree. What about Just Nothing? Using GHCI again, it says Just Nothing :: Maybe (Maybe a) which is also perfectly valid, but what about the value that this a Nothing embedded within an arbitrary number, or even an infinite number, of Justs. ie, what is the type of this value:
foo = Just foo
Haskell doesn't actually allow such a definition, but with a slight tweak we can make such a type:
data Fix a = In { out :: a (Fix a) }
just :: Fix Maybe -> Fix Maybe
just = In . Just
nothing :: Fix Maybe
nothing = In Nothing
foo :: Fix Maybe
foo = just foo
Wooh, close enough! Using the same type, we can create arbitrarily nested nothings:
bar :: Fix Maybe
bar = just (just (just (just nothing)))
Aside: Peano arithmetic anyone?
fromInt :: Int -> Fix Maybe
fromInt 0 = nothing
fromInt n = just $ fromInt (n - 1)
toInt :: Fix Maybe -> Int
toInt (In Nothing) = 0
toInt (In (Just x)) = 1 + toInt x
This Fix Maybe type is a bit boring. Here's a type whose fixed-point is a list:
data L a r = Nil | Cons a r
type List a = Fix (L a)
This data type is going to be instrumental in demonstrating some recursion patterns.
Useful Fact: The r in Cons a r is called a recursion site
Catamorphism
A catamorphism is an operation that breaks a structure down. The catamorphism for lists is better known as a fold. Now the type of a catamorphism can be expressed like so:
cata :: (T a -> a) -> Fix T -> a
Which can be written equivalently as:
cata :: (T a -> a) -> (Fix T -> a)
Or in English as:
You give me a function that reduces a data type to a value and I'll give you a function that reduces it's fixed point to a value.
Actually, I lied, the type is really:
cata :: Functor T => (T a -> a) -> Fix T -> a
But the principle is the same. Notice, T is only parameterized over the type of the recursion sites, so the Functor part is really saying "Give me a way of manipulating all the recursion sites".
Then cata can be defined as:
cata f = f . fmap (cata f) . out
This is quite dense, let me elaborate. It's a three step process:
First, We're given a Fix t, which is a difficult type to play with, we can make it easier by applying out (from the definition of Fix) giving us a t (Fix t).
Next we want to convert the t (Fix t) into a t a, which we can do, via wishful thinking, using fmap (cata f); we're assuming we'll be able to construct cata.
Lastly, we have a t a and we want an a, so we just use f.
Earlier I said that the catamorphism for a list is called fold, but cata doesn't look much like a fold at the moment. Let's define a fold function in terms of cata.
Recapping, the list type is:
data L a r = Nil | Cons a r
type List a = Fix (L a)
This needs to be a functor to be useful, which is straight forward:
instance Functor (L a) where
fmap _ Nil = Nil
fmap f (Cons a r) = Cons a (f r)
So specializing cata we get:
cata :: (L x a -> a) -> List x -> a
We're practically there:
construct :: (a -> b -> b) -> b -> L a b -> b
construct _ x (In Nil) = x
construct f _ (In (Cons e n)) = f e n
fold :: (a -> b -> b) -> b -> List a -> b
fold f m = cata (construct f m)
OK, catamorphisms break data structures down one layer at a time.
Anamorphisms
Anamorphisms over lists are unfolds. Unfolds are less commonly known than there fold duals, they have a type like:
unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
As you can see anamorphisms build up data structures. Here's the more general type:
ana :: Functor a => (a -> t a) -> a -> Fix t
This should immediately look quite familiar. The definition is also reminiscent of the catamorphism.
ana f = In . fmap (ana f) . f
It's just the same thing reversed. Constructing unfold from ana is even simpler than constructing fold from cata. Notice the structural similarity between Maybe (a, b) and L a b.
convert :: Maybe (a, b) -> L a b
convert Nothing = Nil
convert (Just (a, b)) = Cons a b
unfold :: (b -> Maybe (a, b)) -> b -> List a
unfold f = ana (convert . f)
Putting theory into practice
filter is an interesting function in that it can be constructed from a catamorphism or from an anamorphism. The other answers to this question (to date) have also used catamorphisms, but I'll define it both ways:
filter p = foldr (\x xs -> if p x then x:xs else xs) []
filter p =
unfoldr (f p)
where
f _ [] =
Nothing
f p (x:xs) =
if p x then
Just (x, xs)
else
f p xs
Yes, yes, I know I used a recursive definition in the unfold version, but forgive me, I taught you lots of theory and anyway filter isn't recursive.
I'd suggest you look at foldr.
Well, are ifs and empty list allowed?
filter = (\f -> (>>= (\x -> if (f x) then return x else [])))
For a list of Integers
filter2::(Int->Bool)->[Int]->[Int]
filter2 f []=[]
filter2 f (hd:tl) = if f hd then hd:filter2 f tl
else filter2 f tl
I couldn't resist answering this question in another way, this time with no recursion at all.
-- This is a type hack to allow the y combinator to be represented
newtype Mu a = Roll { unroll :: Mu a -> a }
-- This is the y combinator
fix f = (\x -> f ((unroll x) x))(Roll (\x -> f ((unroll x) x)))
filter :: (a -> Bool) -> [a] -> [a]
filter =
fix filter'
where
-- This is essentially a recursive definition of filter
-- except instead of calling itself, it calls f, a function that's passed in
filter' _ _ [] = []
filter' f p (x:xs) =
if p x then
(x:f p xs)
else
f p xs