'IsList' instance for GADT - list

I have troubles implementing IsList instance for GADT which represents structure of values inside nested arrays. Here is complete code:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
import GHC.Exts (IsList (..))
data ValType = TInt | TList
data Val (t :: ValType) where
I :: Int -> Val 'TInt
L :: [Val a] -> Val 'TList
instance Show (Val t) where
show (I i) = "I " ++ show i
show (L a) = show a
instance IsList (Val 'TList) where
type Item (Val 'TList) = forall a . Val a
fromList = L
toList = error "Not implemented!"
I see such error:
GADT.hs:20:10: error:
• Illegal polymorphic type: forall (a :: ValType). Val a
• In the type instance declaration for ‘Item’
In the instance declaration for ‘IsList (Val 'TList)’
|
20 | type Item (Val 'TList) = forall a . Val a
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I partially understand why I have this error. But I would like know if it's possible to implement IsList instance for Val type?

IsList doesn't seem suited to this since the item type Item l must be determined by the list type l. However, overloading of lists can be pushed further with RebindableSyntax:
{-# LANGUAGE RebindableSyntax, OverloadedLists #-}
fromListN :: _Int -> [Val a] -> Val 'TList
fromListN _ = L
Now [[I 3, I 2]] is sugar for fromListN 1 [fromListN 2 [I 3, I 2]], which reduces to L [L [I 3, I 2]].
We can keep the original behavior using a type class like IsList, but which decouples the item and list types.
class IsList item l where
fromListN :: Int -> [item] -> l
instance IsList (Val a) (Val 'TList) where
fromListN _ = L
instance (item ~ item') => IsList item [item'] where
fromListN _ = id

You are throwing away information by only storing the fact that an L ... contains a list of Val as in its type. If you keep this information around
data ValType = TInt | TList ValType
data Val (t :: ValType) where
I :: Int -> Val 'TInt
L :: [Val a] -> Val ('TList a)
then it becomes possible to implement an instance for the IsList type class from the standard library:
instance IsList (Val ('TList a)) where
type Item (Val ('TList a)) = Val a
fromList = L
toList (L xs) = xs
-- (For completeness, this example requires the OverloadedLists extension)
example :: String
example = show ([I 1, I 2, I 3] :: Val ('TList TInt))
Also note that you can implement toList. Because this toList has type Val ('TList a) -> [Val a] it cannot be passed a non-list, so the above implementation is not partial. You can verify this type yourself by using a type hole: toList = _. You can also verify that an (attempt at) implementation like the following will give a type error: toList (I x) = undefined.
Every item in the list must have the same type (you cannot have mix integers with lists within a single list, for example), but this was also the case for the original code from the question.

Related

replicate function for a length-indexed list using GHC.TypeLits and singletons

I'm trying to write a replicate function for a length-indexed list using the machinery from GHC.TypeLits, singletons, and constraints.
The Vect type and signature for replicateVec are given below:
data Vect :: Nat -> Type -> Type where
VNil :: Vect 0 a
VCons :: a -> Vect (n - 1) a -> Vect n a
replicateVec :: forall n a. SNat n -> a -> Vect n a
How can you write this replicateVec function?
I have a version of replicateVec that compiles and type checks, but it appears to go into an infinite loop when run. The code is below. I have added comments to try to make the laws and proofs I am using a little easier to understand:
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeInType #-}
module VectStuff where
import Data.Constraint ((:-)(Sub), Dict(Dict))
import Data.Kind (Type)
import Data.Singletons.Decide (Decision(Disproved, Proved), Refuted, (:~:)(Refl), (%~))
import Data.Singletons.Prelude (PNum((-)), sing)
import Data.Singletons.TypeLits (SNat, Sing(SNat))
import GHC.TypeLits (CmpNat, KnownNat, Nat)
import Unsafe.Coerce (unsafeCoerce)
data Vect :: Nat -> Type -> Type where
VNil :: Vect 0 a
VCons :: forall n a. a -> Vect (n - 1) a -> Vect n a
deriving instance Show a => Show (Vect n a)
-- This is used to define the two laws below.
axiom :: Dict a
axiom = unsafeCoerce (Dict :: Dict ())
-- | This law says that if we know that #n# is not 0, then it MUST be
-- greater than 0.
nGT0CmpNatLaw :: (Refuted (n :~: 0)) -> Dict (CmpNat n 0 ~ 'GT)
nGT0CmpNatLaw _ = axiom
-- | This law says that if we know that #n# is greater than 0, then we know
-- that #n - 1# is also a 'KnownNat'.
cmpNatGT0KnownNatLaw :: forall n. (CmpNat n 0 ~ 'GT) :- KnownNat (n - 1)
cmpNatGT0KnownNatLaw = Sub axiom
-- | This is a proof that if we have an #n# that is greater than 0, then
-- we can get an #'SNat' (n - 1)#
sNatMinus1 :: forall n. (CmpNat n 0 ~ 'GT) => SNat n -> SNat (n - 1)
sNatMinus1 SNat =
case cmpNatGT0KnownNatLaw #n of
Sub Dict -> SNat
-- | This is basically a combination of the other proofs. If we have a
-- #SNat n# and we know that it is not 0, then we can get an #SNat (n -1)#
-- that we know is a 'KnownNat'.
nGT0Proof ::
forall n.
Refuted (n :~: 0)
-> SNat n
-> (SNat (n - 1), Dict (KnownNat (n - 1)))
nGT0Proof f snat =
case nGT0CmpNatLaw f of
Dict ->
case cmpNatGT0KnownNatLaw #n of
Sub d -> (sNatMinus1 snat, d)
replicateVec :: forall n a. SNat n -> a -> Vect n a
replicateVec snat a =
-- First we check if #snat# is 0.
case snat %~ (sing #_ #0) of
-- If we get a proof that #snat# is 0, then we just return 'VNil'.
Proved Refl -> VNil
-- If we get a proof that #snat# is not 0, then we use 'nGT0Proof'
-- to get #n - 1#, and pass that to 'replicateVec' recursively.
Disproved f ->
case nGT0Proof f snat of
(snat', Dict) -> VCons a $ replicateVec snat' a
However, for some reason this replicateVec function goes into an endless loop when I try to run it:
> replicateVec (sing #_ #3) "4"
["4","4","4","4","4","4","4","4","4","4","4","4",^CInterrupted.
Why is this happening? How can I write the replicateVec function correctly?
axiom :: Dict a is very unsafe because the runtime representation of a Dict a depends on the constraint a (which corresponds to a dictionary that is captured by the Dict constructor).
A KnownNat constraint corresponds to an integer value at runtime, so it is not correct to construct a Dict of KnownNat using unsafeCoerce on a dummy dictionary (in cmpNatGT0KnownNatLaw). In particular, this integer is used in replicateVec to check whether the integer is 0.
Type equalities (~) are special in that they have no meaningful runtime representation, hence axiom-atizing equalities, if they are correct, technically does not lead to bad runtime behavior because the coerced dictionary is never used, but coercing from Dict () to a Dict (a ~ b) is certainly not a supported use of unsafeCoerce. Coercing between equalities might be more reliable.
To solve KnownNat constraints, constraints internally associates the type-level operations to their term-level counterparts, see magic in Data.Constraints.Nat and reconstructs the KnownNat dictionary based on implicit knowledge about how GHC represents type classes.
Anyway, for an inductive construction like replicate, we can avoid KnownNat, and use a different singleton type that reflects the inductive nature of Nat.
data Sing n where
Z :: Sing 0
S :: Sing n -> Sing (1 + n)
This singleton is actually annoying to use because (+) is not injective. (\x -> (1 + x) technically is injective, but GHC can't tell that much.) It would be easier with an actually inductively defined Nat, but still, with the right set of constraints, we can do some things. For example, singleton reflection (mapping from the type-level n to a Sing n value):
class SingN n where
singN :: Sing n
instance {-# OVERLAPPING #-} SingN 0 where
singN = Z
instance (n ~ (1 + n'), n' ~ (n - 1), SingN n') => SingN n where
singN = S (singN #n')
The list type should be similarly structured:
data List n a where
Nil :: List 0 a
Cons :: a -> List n a -> List (1 + n) a
The reason to set up the type index n this way instead of Sing (n-1) -> Sing n and a -> List (n-1) a -> List n a is to forbid some silly values:
oops :: Sing 0
oops = S undefined
ouch :: List 0 ()
ouch = Cons () undefined
which would be a problem because functions would actually need to handle those cases which make no sense.
replicate turns out to be straightforward to implement because List and Sing have a lot of structure in common.
replicate :: Sing n -> a -> List n a
replicate Z _ = Nil
replicate (S n) a = Cons a (replicate n a)
We can now apply replicate as follows:
replicate (singN #3) "x"
Compilable gist

Generating a type annotation using DataKinds within a TH QuasiQuote

In a haskell project using template haskell, I am trying to generate an expression that has a type annotation as a phantom type.
A simple example would be a situation with DataKinds and KindSignatures like:
{-# LANGUAGE DataKinds, KindSignatures #-}
data Foo = A | B
data GenMe (w :: Foo) = GenMe Int
[| $(generate some code) :: GenMe $(genType someCompileTimeData) |]
How can I write a function, like genType such that
genType :: Foo -> Q Type
lifting just lifts the variable holding the compile time Foo value? I don't know which constructor to use from the Type Data Constructors
to make data kinds.
Any thoughts? Thanks!
Another way to slice this problem is to define a promote :: Exp -> Maybe Type function and then use lift on Foo.
-- | Takes the AST for an expression and tries to produce the corresponding
-- promoted type AST.
promote :: Exp -> Q Type
promote (VarE n) = fail ("Cannot promote variable " ++ show n)
promote (ConE n) = pure (PromotedT n)
promote (LitE l) = LitT <$> promoteLit l
promote (TupE es) = foldl AppT (PromotedTupleT (length es)) <$> (traverse promote es)
promote (ListE es) = foldr (\x xs -> AppT (AppT PromotedConsT x) xs) PromotedNilT <$> (traverse promote es)
promote (ParensE e) = ParensT <$> promote e
promote (AppE e1 e2) = AppT <$> promote e1 <*> promote e2
promote (InfixE (Just e1) e2 (Just e3)) = AppT <$> (AppT <$> promote e2 <*> promote e1) <*> promote e3
promote _ = fail "Either impossible to promote or unimplemented"
-- | Promote an expression literal to a type one
promoteLit :: Lit -> Q TyLit
promoteLit (StringL s) = pure (StrTyLit s)
promoteLit (IntegerL i) = pure (NumTyLit i)
promoteLit _ = fail "Expression literal cannot be promoted"
Then, I think something along the lines of the following should work
ghci> :set -XDeriveLift -XDataKinds -XKindSignatures -XTemplateHaskell -XQuasiQuotes
ghci> data Foo = A | B deriving (Lift)
ghci> foo1 = A
ghci> data GenMe (w :: Foo) = GenMe Int
ghci> runQ [| GenMe 1 :: GenMe $(promote =<< lift foo1) |]
SigE (AppE (ConE Ghci5.GenMe) (LitE (IntegerL 1))) (AppT (ConT Ghci5.GenMe) (PromotedT Ghci3.A))

Haskell data.list.class usage

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.

Convert 'a list to a Set?

Is it really true that OCaml doesn't have a function which converts from a list to a set?
If that is the case, is it possible to make a generic function list_to_set? I've tried to make a polymorphic set without luck.
Fundamental problem: Lists can contain elements of any types. Sets (assuming you mean the Set module of the standard library), in contrary, rely on a element comparison operation to remain balanced trees. You cannot hope to convert a t list to a set if you don't have a comparison operation on t.
Practical problem: the Set module of the standard library is functorized: it takes as input a module representing your element type and its comparison operation, and produces as output a module representing the set. Making this work with the simple parametric polymoprhism of lists is a bit sport.
To do this, the easiest way is to wrap your set_of_list function in a functor, so that it is itself parametrized by a comparison function.
module SetOfList (E : Set.OrderedType) = struct
module S = Set.Make(E)
let set_of_list li =
List.fold_left (fun set elem -> S.add elem set) S.empty li
end
You can then use for example with the String module, which provides a suitable compare function.
module SoL = SetOfList(String);;
SoL.S.cardinal (SoL.set_of_list ["foo"; "bar"; "baz"]);; (* returns 3 *)
It is also possible to use different implementation of sets which are non-functorized, such as Batteries and Extlib 'PSet' implementation (documentation). The functorized design is advised because it has better typing guarantees -- you can't mix sets of the same element type using different comparison operations.
NB: of course, if you already have a given set module, instantiated form the Set.Make functor, you don't need all this; but you conversion function won't be polymorphic. For example assume I have the StringSet module defined in my code:
module StringSet = Set.Make(String)
Then I can write stringset_of_list easily, using StringSet.add and StringSet.empty:
let stringset_of_list li =
List.fold_left (fun set elem -> StringSet.add elem set) StringSet.empty li
In case you're not familiar with folds, here is a direct, non tail-recursive recursive version:
let rec stringset_of_list = function
| [] -> StringSet.empty
| hd::tl -> StringSet.add hd (stringset_of_list tl)
Ocaml 3.12 has extensions (7,13 Explicit naming of type variables and 7,14 First-class modules) that make it possible to instantiate and pass around modules for polymorphic values.
In this example, the make_set function returns a Set module for a given comparison function and the build_demo function constructs a set given a module and a list of values:
let make_set (type a) compare =
let module Ord = struct
type t = a
let compare = compare
end
in (module Set.Make (Ord) : Set.S with type elt = a)
let build_demo (type a) set_module xs =
let module S = (val set_module : Set.S with type elt = a) in
let set = List.fold_right S.add xs S.empty in
Printf.printf "%b\n" (S.cardinal set = List.length xs)
let demo (type a) xs = build_demo (make_set compare) xs
let _ = begin demo ['a', 'b', 'c']; demo [1, 2, 3]; end
This doesn't fully solve the problem, though, because the compiler doesn't allow the return value to have a type that depends on the module argument:
let list_to_set (type a) set_module xs =
let module S = (val set_module : Set.S with type elt = a) in
List.fold_right S.add xs S.empty
Error: This `let module' expression has type S.t
In this type, the locally bound module name S escapes its scope
A possible work-around is to return a collection of functions that operate on the hidden set value:
let list_to_add_mem_set (type a) set_module xs =
let module S = (val set_module : Set.S with type elt = a) in
let set = ref (List.fold_right S.add xs S.empty) in
let add x = set := S.add x !set in
let mem x = S.mem x !set in
(add, mem)
If you don't mind a very crude approach, you can use the polymorphic hash table interface. A hash table with an element type of unit is just a set.
# let set_of_list l =
let res = Hashtbl.create (List.length l)
in let () = List.iter (fun x -> Hashtbl.add res x ()) l
in res;;
val set_of_list : 'a list -> ('a, unit) Hashtbl.t = <fun>
# let a = set_of_list [3;5;7];;
val a : (int, unit) Hashtbl.t = <abstr>
# let b = set_of_list ["yes";"no"];;
val b : (string, unit) Hashtbl.t = <abstr>
# Hashtbl.mem a 5;;
- : bool = true
# Hashtbl.mem a 6;;
- : bool = false
# Hashtbl.mem b "no";;
- : bool = true
If you just need to test membership, this might be good enough. If you wanted other set operations (like union and intersection) this isn't a very nice solution. And it's definitely not very elegant from a typing standpoint.
Just extend the original type, as shown in
http://www.ffconsultancy.com/ocaml/benefits/modules.html
for the List module:
module StringSet = Set.Make (* define basic type *)
(struct
type t = string
let compare = Pervasives.compare
end)
module StringSet = struct (* extend type with more operations *)
include StringSet
let of_list l =
List.fold_left
(fun s e -> StringSet.add e s)
StringSet.empty l
end;;
Using the core library you could do something like:
let list_to_set l =
List.fold l ~init:(Set.empty ~comparator:Comparator.Poly.comparator)
~f:Set.add |> Set.to_list
So for example:
list_to_set [4;6;3;6;3;4;3;8;2]
-> [2; 3; 4; 6; 8]
Or:
list_to_set ["d";"g";"d";"a"]
-> ["a"; "d"; "g"]

Implementing filter using HoF in Haskell

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