What is a Lambda Calculus equivalent of the map function in Haskell? - list

The map function returns a list constructed by applying a function (the first argument) to all items in a list passed as the second argument.
I'm trying to figure out what this would look like if displayed in Lambda Calculus notation. Can anyone give an example?

Since this is tagged haskell I'll write the answer in Haskell, but building everything on functions like you would in lambda calculus. This generally incurs carrying around an extra type parameter r for the continuation-passing style.
Lists are usually can be encoded as deconstruction-matchers: (this is Scott encoding, as the comments inform me)
newtype List r a = List { deconstructList
:: r -- ^ `Nil` case
-> (a -> List r a -> r) -- ^ `Cons` case
-> r -- ^ result
}
Now we want to give this a Functor instance. As with other problems, you can let the compiler guide you:
instance Functor (List r) where
fmap f (List l) = List _
This will prompt
LambdaList.hs:8:26: error:
• Found hole: _ :: r -> (b -> List r b -> r) -> r
Where: ‘b’ is a rigid type variable bound by
the type signature for:
fmap :: forall a b. (a -> b) -> List r a -> List r b
at LambdaList.hs:8:3-6
‘r’ is a rigid type variable bound by
the instance declaration
at LambdaList.hs:7:10-25
• In the first argument of ‘List’, namely ‘_’
In the expression: List _
In an equation for ‘fmap’: fmap f (List l) = List _
• Relevant bindings include
l :: r -> (a -> List r a -> r) -> r (bound at LambdaList.hs:8:16)
f :: a -> b (bound at LambdaList.hs:8:8)
fmap :: (a -> b) -> List r a -> List r b
(bound at LambdaList.hs:8:3)
Valid hole fits include
const :: forall a b. a -> b -> a
with const #r #(b -> List r b -> r)
(imported from ‘Prelude’ at LambdaList.hs:1:1
(and originally defined in ‘GHC.Base’))
return :: forall (m :: * -> *) a. Monad m => a -> m a
with return #((->) (b -> List r b -> r)) #r
(imported from ‘Prelude’ at LambdaList.hs:1:1
(and originally defined in ‘GHC.Base’))
pure :: forall (f :: * -> *) a. Applicative f => a -> f a
with pure #((->) (b -> List r b -> r)) #r
(imported from ‘Prelude’ at LambdaList.hs:1:1
(and originally defined in ‘GHC.Base’))
|
8 | fmap f (List l) = List _
| ^
So we're supposed to define a function; well then it's probably a good idea to start with lambda-binding some arguments:
instance Functor (List r) where
fmap f (List l) = List $ \nilCs consCs -> _
LambdaList.hs:8:45: error:
• Found hole: _ :: r
Where: ‘r’ is a rigid type variable bound by
the instance declaration
at LambdaList.hs:7:10-25
• In the expression: _
In the second argument of ‘($)’, namely ‘\ nilCs consCs -> _’
In the expression: List $ \ nilCs consCs -> _
• Relevant bindings include
consCs :: b -> List r b -> r (bound at LambdaList.hs:8:35)
nilCs :: r (bound at LambdaList.hs:8:29)
l :: r -> (a -> List r a -> r) -> r (bound at LambdaList.hs:8:16)
f :: a -> b (bound at LambdaList.hs:8:8)
fmap :: (a -> b) -> List r a -> List r b
(bound at LambdaList.hs:8:3)
Valid hole fits include nilCs :: r (bound at LambdaList.hs:8:29)
The CPS-result should still come from the original list, so we need to use that at this point – with args still TBD, but the nil case won't change so we can right away pass that too:
instance Functor (List r) where
fmap f (List l) = List $ \nilCs consCs -> l nilCs _
LambdaList.hs:8:53: error:
• Found hole: _ :: a -> List r a -> r
Where: ‘a’ is a rigid type variable bound by
the type signature for:
fmap :: forall a b. (a -> b) -> List r a -> List r b
at LambdaList.hs:8:3-6
‘r’ is a rigid type variable bound by
the instance declaration
at LambdaList.hs:7:10-25
• In the second argument of ‘l’, namely ‘_’
In the expression: l nilCs _
In the second argument of ‘($)’, namely
‘\ nilCs consCs -> l nilCs _’
• Relevant bindings include
consCs :: b -> List r b -> r (bound at LambdaList.hs:8:35)
nilCs :: r (bound at LambdaList.hs:8:29)
l :: r -> (a -> List r a -> r) -> r (bound at LambdaList.hs:8:16)
f :: a -> b (bound at LambdaList.hs:8:8)
fmap :: (a -> b) -> List r a -> List r b
(bound at LambdaList.hs:8:3)
So it's again function-time, i.e. bind some arguments:
instance Functor (List r) where
fmap f (List l) = List
$ \nilCs consCs -> l nilCs $ \lHead lTail -> _
LambdaList.hs:9:51: error:
• Found hole: _ :: r
Where: ‘r’ is a rigid type variable bound by
the instance declaration
at LambdaList.hs:7:10-25
• In the expression: _
In the second argument of ‘($)’, namely ‘\ lHead lTail -> _’
In the expression: l nilCs $ \ lHead lTail -> _
• Relevant bindings include
lTail :: List r a (bound at LambdaList.hs:9:42)
lHead :: a (bound at LambdaList.hs:9:36)
consCs :: b -> List r b -> r (bound at LambdaList.hs:9:15)
nilCs :: r (bound at LambdaList.hs:9:9)
l :: r -> (a -> List r a -> r) -> r (bound at LambdaList.hs:8:16)
f :: a -> b (bound at LambdaList.hs:8:8)
(Some bindings suppressed; use -fmax-relevant-binds=N or -fno-max-relevant-binds)
Valid hole fits include nilCs :: r (bound at LambdaList.hs:9:9)
At this point we have a lot in scope that could conceivably be used, but a good rule of thumb is that we should probably use all of them at least once, so let's bring in consCs, with two TBD arguments:
instance Functor (List r) where
fmap f (List l) = List
$ \nilCs consCs -> l nilCs $ \lHead lTail -> consCs _ _
LambdaList.hs:9:58: error:
• Found hole: _ :: b
Where: ‘b’ is a rigid type variable bound by
the type signature for:
fmap :: forall a b. (a -> b) -> List r a -> List r b
at LambdaList.hs:8:3-6
• In the first argument of ‘consCs’, namely ‘_’
In the expression: consCs _ _
In the second argument of ‘($)’, namely
‘\ lHead lTail -> consCs _ _’
• Relevant bindings include
lTail :: List r a (bound at LambdaList.hs:9:42)
lHead :: a (bound at LambdaList.hs:9:36)
consCs :: b -> List r b -> r (bound at LambdaList.hs:9:15)
nilCs :: r (bound at LambdaList.hs:9:9)
l :: r -> (a -> List r a -> r) -> r (bound at LambdaList.hs:8:16)
f :: a -> b (bound at LambdaList.hs:8:8)
(Some bindings suppressed; use -fmax-relevant-binds=N or -fno-max-relevant-binds)
Ok, there's only one way to obtain a b value: using f, which needs an a as its argument, for which we have exactly one, namely lHead:
instance Functor (List r) where
fmap f (List l) = List
$ \nilCs consCs -> l nilCs
$ \lHead lTail -> consCs (f lHead) _
LambdaList.hs:9:60: error:
• Found hole: _ :: List r b
Where: ‘b’ is a rigid type variable bound by
the type signature for:
fmap :: forall a b. (a -> b) -> List r a -> List r b
at LambdaList.hs:8:3-6
‘r’ is a rigid type variable bound by
the instance declaration
at LambdaList.hs:7:10-25
• In the second argument of ‘consCs’, namely ‘_’
In the expression: consCs _ _
In the second argument of ‘($)’, namely
‘\ lHead lTail -> consCs _ _’
• Relevant bindings include
lTail :: List r a (bound at LambdaList.hs:9:42)
lHead :: a (bound at LambdaList.hs:9:36)
consCs :: b -> List r b -> r (bound at LambdaList.hs:9:15)
nilCs :: r (bound at LambdaList.hs:9:9)
l :: r -> (a -> List r a -> r) -> r (bound at LambdaList.hs:8:16)
f :: a -> b (bound at LambdaList.hs:8:8)
(Some bindings suppressed; use -fmax-relevant-binds=N or -fno-max-relevant-binds)
Here we have a bit of a problem: no List r b is in scope or in the result of any of the bindings. However, what does yield a List r b is the function we're just defining here: fmap f. In standard lambda calculus you can't actually recursively call a definition (you need to use a fixpoint combinator to emulate it), but I'll ignore this here. This is a valid Haskell solution:
instance Functor (List r) where
fmap f (List l) = List
$ \nilCs consCs -> l nilCs
$ \lHead lTail -> consCs (f lHead) (fmap f lTail)
Or written in lambda style (erasing the List newtype constructor),
map = \f l ν ζ ⟼ l ν (\h t ⟼ ζ (f h) (map f t))

Related

How to extract the maximum element from a List in haskell?

I am new to Haskell and I want to extract the maximum element from a given List so that I end up with the maximum element x and the remaining list xs (not containing x). It can be assumed that the elements of the list are unique.
The type of function I want to implement is somewhat like this:
maxElement :: (Ord b) => (a -> b) -> [a] -> (a, [a])
Notably, the first argument is a function that turns an element into a comparable form. Also, this function is non-total as it would fail given an empty List.
My current approach fails to keep the elements in the remainder list in place, meaning given [5, 2, 4, 6] it returns (6, [2, 4, 5]) instead of (6, [5, 2, 4]). Furthermore, it feels like there should be a nicer looking solution.
compareElement :: (Ord b) => (a -> b) -> a -> (b, (a, [a])) -> (b, (a, [a]))
compareElement p x (s, (t, ts))
| s' > s = (s', (x, t:ts))
| otherwise = (s, (t, x:ts))
where s' = p x
maxElement :: (Ord b) => (a -> b) -> [a] -> (a, [a])
maxElement p (t:ts) = snd . foldr (compareElement p) (p t, (t, [])) $ ts
UPDATE
Thanks to the help of the answer of #Ismor and the comment #chi I've updated my implementation and I feel happy with the result.
maxElement :: (Ord b) => (a -> b) -> [a] -> Maybe (b, a, [a], [a])
maxElement p =
let
f x Nothing = Just (p x, x, [], [x])
f x (Just (s, m, xs, ys))
| s' > s = Just (s', x, ys, x:ys)
| otherwise = Just (s, m, x:xs, x:ys)
where s' = p x
in
foldr f Nothing
The result is either Nothing when the given list is empty or Maybe (_, x, xs, _). I could write another "wrapper" function with the originally intended type and call maxElement under the hood, but I believe this also ok.
This answer is more of a personal advise than a proper answer. As a rule of thumb, whenever you find yourself trying to write a loop with an accumulator (as in this case), try to write it in this form
foldr updateAccumulator initialAccumulator --use foldl' if it is better for your use case`
then, follow the types to complete It as shown below
Step 1
Write undefined where needed. You know the function should look like this
maxElement :: (Ord b) => (a -> b) -> [a] -> (a, [a])
maxElement f xs = foldr updateAccumulator initalAccumulator xs
where
updateAccumulator = undefined
initialAccumulator = undefined
Step 2
"Chase the type". Meaning that using the type of maxElement and foldr you can
deduce the types of updateAccumulator and initialAccumulator. Try to reduce polymorphism as much as you can. In this case:
You know foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
You know your Foldable is [] so It'd be easier to substitute
Hence foldr :: (a -> b -> b) -> b -> [a] -> b
Because you want foldr to produce (a, [a]) you know b ~ (a, [a])
etc... keep going until you know what types your functions have. You can use ghc typed holes in this process, which is a very nice feature
maxElement :: (Ord b) => (a -> b) -> [a] -> (a, [a])
maxElement f xs = foldr updateAccumulator initalAccumulator xs
where
-- Notice that you need to enable an extension to write type signature in where clause
-- updateAccumulator :: a -> (a, [a]) -> (a, [a])
updateAccumulator newElement (currentMax, currentList) = undefined
-- initialAccumulator :: (a, [a])
initialAccumulator = undefined
Step 3
Now, writing down the function should be easier. Below I leave some incomplete parts for you to fill
maxElement :: (Ord b) => (a -> b) -> [a] -> (a, [a])
maxElement f xs = foldr updateAccumulator initalAccumulator xs
where
-- updateAccumulator :: a -> (a, [a]) -> (a, [a])
updateAccumulator newElement (currentMax, currentList) =
if f newElement > f currentMax
then undefined -- How does the accumulator should look when the new element is bigger than the previous maximum?
else undefined
-- initialAccumulator :: (a, [a])
initialAccumulator = undefined -- Tricky!, what does happen if xs is empty?
Hope this clarifies some doubts, and understand I don't give you a complete answer.
I don't know if you were trying to avoid using certain library functions, but Data.List has a maximumBy and deleteBy that do exactly what you want:
import Data.Function (on)
import Data.List (deleteBy, maximumBy)
import Data.Ord (comparing)
maxElement :: (Ord b) => (a -> b) -> [a] -> (a, [a])
maxElement f xs = (max, remaining) where
max = maximumBy (comparing f) xs
remaining = deleteBy ((==) `on` f) max xs
Thanks to the help of the answer of #Ismor and the comment #chi I've updated my implementation and I feel happy with the result.
maxElement :: (Ord b) => (a -> b) -> [a] -> Maybe (b, a, [a], [a])
maxElement p =
let
f x Nothing = Just (p x, x, [], [x])
f x (Just (s, m, xs, ys))
| s' > s = Just (s', x, ys, x:ys)
| otherwise = Just (s, m, x:xs, x:ys)
where s' = p x
in
foldr f Nothing
The result is either Nothing when the given list is empty or Maybe (_, x, xs, _). I could write another "wrapper" function with the originally intended type and call maxElement under the hood, but I believe this is also ok.
Construct the list of all the "zippers" over the input list, then take the maximumBy (comparing (\(_,x,_) -> foo x)) of it, where foo is your Ord b => a -> b function, then reverse-append the first half to the second and put it in a tuple together with the middle element.
A zipper over a list xs is a triple (revpx, x, suffx) where xs == reverse revpx ++ [x] ++ suffx:
> :t comparing (\(_,x,_) -> x)
comparing (\(_,x,_) -> x)
:: Ord a => (t, a, t1) -> (t, a, t1) -> Ordering
Constructing the zippers list is an elementary exercise (see the function picks3 there).
About your edited solution, it can be coded as a foldr over the tails so it's a bit clearer what's going on there:
maxElement :: (Ord b) => (a -> b) -> [a] -> Maybe (b, a, [a])
maxElement p [] = Nothing
maxElement p xs = Just $ foldr f undefined (tails xs)
where
f [x] _ = (p x, x, [])
f (x:xs) (b, m, ys)
| b' > b = (b', x, xs) -- switch over
| otherwise = (b, m, x:ys)
where b' = p x
It's also a bit cleaner as it doesn't return the input list's copy for no apparent reason, as your version did since it used it for internal purposes.
Both ways are in fact emulating a paramorphism.

Haskell recursively applying function to every element but first?

So I've been doing this program which receives a function f, a number a and a list b and it should return a list [a, f(a,b), f(f(a,b),b, ..] iterating through the list b and using recursion. Do you guys know how I can optimize my code?
calculate :: (a -> b -> a) -> a -> [b] -> [a]
help :: (a -> b -> a) -> a -> [b] -> [a]
help f a (x:xs) = (f a x) : (calculate f (f a x) xs)
help f a [] = []
calculate f a b = a : (help f a b)
calculate f a b = tail . concatMap (replicate 2) . scanl f a $ b.
The replicate bit is probably in error. If so, then simply calculate = scanl.
This translates the code, as the "[a, f(a,b), f(f(a,b),b, ..]" from the text contradicts it (and it contradicts the text itself, which talks of "iterating through the list b").

Haskell: Calculate the length of a list using (curry snd)

I was given an assignment to calculate the length of a list using the foldr Haskell function, so I did these two examples
flength :: [a] -> Int
flength = foldr (\ _ n -> n+1) 0
flength' :: [a] -> Int
flength' l = foldr aux 0 l
where
aux _ n = n+1
Then, as a personal challenge, the professor asked us to use the snd function and yesterday I came up with this:
flength'' :: [a] -> Int
flength'' = foldr ((+1).(curry snd)) 0
What I want to happen is that this function will turn the head of the list h and the accumulator 0 into the pair (h,0) then return 0 and after that apply it to the function (+1)
I expected this to be done recursively, effectively giving me the length of the list at the end.
Instead, I get this error message:
[1 of 1] Compiling Main ( f1.hs, interpreted )
f1.hs:54:24: error:
* No instance for (Num (Int -> Int))
arising from an operator section
(maybe you haven't applied a function to enough arguments?)
* In the first argument of `(.)', namely `(+ 1)'
In the first argument of `foldr', namely `((+ 1) . (curry snd))'
In the expression: foldr ((+ 1) . (curry snd)) 0 xs
Failed, modules loaded: none.
Why is this happening and how can I get this code to work?
Let us lay all our tools in front of us, like a good artisan does:
foldr :: (a -> b -> b) -> b -> [a] -> b
snd :: (a, b) -> b
First, we note that snd and foldr do not really fit well. So let's use curry, just like you did, and add curry snd to our small tool library:
foldr :: (a -> b -> b) -> b -> [a] -> b
curry snd :: a -> b -> b
This looks very promising. Now we need to add 1 to the result of curry snd, otherwise we're just writing flip const. Let's start with a lambda:
\a b -> 1 + curry snd a b
= \a b -> ((+1) . curry snd a) b
We can now shove of b and end up with
\a -> (+1) . curry snd a
= \a -> (.) (+1) (curry snd a)
= \a -> ((.) (+1)) (curry snd a)
= \a -> (((.) (+1)) . curry snd) a
Now we can eta-reduce a from both sides too and end up with
(((.) (+1)) . curry snd) = ((+1) . ) . curry snd
Therefore, your third variant would be
flength'' = foldr (((+1) . ) . curry snd) 0
Now, why did you get your error message? You were close with (+1) . curry snd, but the types don't work out:
(+1) :: Int -> Int
-- v v
(.) :: (b -> c) -> (a -> b ) -> a -> c
curry snd :: t -> (x -> x)
^ ^
But in your case, the bs in (.)'s signature didn't match. One of them was an Int, the other was a function.
TL;DR: If you want to write f (g x y) point-free, write ((f.) . g)

How to do stateful list operations in haskell

I need an operation which iterates over a list and produces a new list, where the new list elements depend on all elements previously seen. To do this I would like to pass an accumulator/state from iteration to iteration.
Think for example of a list of tuples, where the components of a tuple can be "undefined". An undefined value shall assume the latest value of the same component earlier in the list, if any. So at any stage I will have a state of defined components, which I need to pass to the next iteration.
So with a list of type [l] and an accumulator/state of type a there will be a function of type
f :: a -> l -> (a,l)
i.e it spits out a new list element and a new accumulator.
Is there a function which allows simply applying f to a list? I looked at fold, scan and unfold, but none of them seem to do the trick.
Edit: While the state monad looks promising, I can only see how I would get the final state, but I fail to see how I would get the new list elements.
There are some standard functions you can use to do what you ask.
It sounds very much like you want mapAccum, so you just need to import Data.List and decide which way round you're accumulating. (I suspect you want mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y]).)
mapAccumL
import Data.List
data Instruction = NoChange | Reset | MoveBy Int
tell :: Int -> Instruction -> (Int,String) -- toy accumulating function
tell n NoChange = (n,"")
tell n Reset = (0,"Reset to zero")
tell n (MoveBy i) = (n+i,"Add "++show i++" to get "++ show (n+i))
which would give
ghci> mapAccumL tell 10 [MoveBy 5, MoveBy 3, NoChange, Reset, MoveBy 7]
(7,["Add 5 to get 15","Add 3 to get 18","","Reset to zero","Add 7 to get 7"])
scanL
But maybe you don't need to use the full power of mapAccum because sometimes the accumulator is what you want in the new list, so scanl :: (a -> b -> a) -> a -> [b] -> [a] will do the trick
act :: Int -> Instruction -> Int
act n NoChange = n
act n Reset = 0
act n (MoveBy i) = n+i
like this:
ghci> scanl act 10 [MoveBy 5, MoveBy 3, NoChange, Reset, MoveBy 7]
[10,15,18,18,0,7]
Definition for mapAccum
Anyway, here's how mapAccumL and mapAccumR are described in Data.List:
mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
mapAccumL _ state [] = (state, [])
mapAccumL f state (x:xs) = (finalstate,y:ys)
where (nextstate, y ) = f state x
(finalstate,ys) = mapAccumL f nextstate xs
The mapAccumL function behaves like a combination of map and foldl; it applies a function to each element of a list, passing an accumulating parameter from left to right, and returning a final value of this accumulator together with the new list.
mapAccumR :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
mapAccumR _ state [] = (state, [])
mapAccumR f state (x:xs) = (finalstate, y:ys)
where (finalstate,y ) = f nextstate x
(nextstate, ys) = mapAccumR f state xs
The mapAccumR function behaves like a combination of map and foldr; it applies a function to each element of a list, passing an accumulating parameter from right to left, and returning a final value of this accumulator together with the new list.
You want mapM in conjunction with the State monad where your accumulator a will be the State. First, to see why you need State, just take your type signature and flip the order of arguments and results:
import Data.Tuple
f :: a -> l -> (a, l)
uncurry f :: (a, l) -> (a, l)
swap . uncurry f . swap :: (l, a) -> (l, a)
curry (swap . uncurry f . swap) :: l -> a -> (l, a)
Or you could just define f to already have the arguments and results in the right order, whichever you prefer. I will call this swapped function f':
f' :: l -> a -> (l, a)
Now lets add an extra set of parentheses around the right half of the type signature of f':
f' :: l -> (a -> (l, a))
That part grouped in parentheses is a State computation where the state is a and the result is l. So I will go ahead and convert it to the State type using the state function from Control.Monad.Trans.State:
state :: (a -> (l, a)) -> State a l
So the converted f' would look like this:
f'' :: l -> State a l
f'' = state . f'
However, the function you really want in the end is something of type:
final :: [l] -> a -> ([l], a)
-- which is really just:
state . final :: [l] -> State a [l]
So that means that I need some function that takes a l -> State a l and converts it to a [l] -> State a [l]. This is precisely what mapM does, except that mapM works for any Monad, not just State:
mapM :: (Monad m) => (a -> m b) -> ([a] -> m [b])
Notice how if we replace m with State a, and set a and b to l, then it has exactly the right type:
mapM :: (l -> State a l) -> ([l] -> State a [l])
f''' :: [l] -> State a [l]
f''' = mapM f''
Now we can unwrap the State using runState to get back a list-threading function of the appropriate type:
final :: [l] -> a -> ([l], a)
final = runState . f'''
So if we combine all those steps into one we get:
final = runState . mapM (state . f')
... where f' is your function written to swap the order of arguments and results. If you choose not to modify your original function then the solution is slightly more verbose:
final = runState . mapM (state . uncurry (swap . curry f . swap))
Without the specifics of what you are actually trying to achieve, getting to an answer is a bit difficult. But it seems to be that if your f had the type:
f :: (a, [l]) -> l -> (a,l)
Then you could define a function, f':
f' :: (a, [l]) -> l -> (a,l)
f' acc#(y, xs) x = (z, x':xs)
where
(z, x') = f acc
Which can then be used in a fold.
foldr f' (e, []) xs
The new signature of f allows it to have access to all preceding elements in the list, and f' adds the new element from the call to f to the list.

List filter using an anamorphism

I implemented a broken filter function using an anamorphism from recursion-schemes Hackage library:
import Data.Functor.Foldable
xfilter :: (a -> Bool) -> [a] -> [a]
xfilter f = ana $ project . phi f
phi :: (a -> Bool) -> [a] -> [a]
phi f (h : t) | not (f h) = t
phi f l = l
The function is not a faithful implementation of filter: xfilter odd [1..5] works, but xfilter odd [0,0] doesn't. I tried to implement "retries" by using explicit recursion in phi and then reimplemented that with a paramorphism, so I ended with ana . para:
xfilter :: (a -> Bool) -> [a] -> [a]
xfilter f = ana . para $ phi where
phi Nil = Nil
phi (Cons h (t, tt)) | f h = Cons h t
phi (Cons h (t, tt)) = tt
This is satisfactory, but I then tried to express retries explicitly in phi and perform them outside:
xfilter :: (a -> Bool) -> [a] -> [a]
xfilter f = ana $ project . retry (phi f)
phi :: (a -> Bool) -> [a] -> Either [a] [a]
phi f (h : t) | not (f h) = Left t
phi f l = Right l
retry f x = case f x of
Right x -> x
Left x -> retry f x
Right means 'produce a new element' and Left means 'retry with a new seed'.
The signature of phi started to look pretty similar to the first argument of apomorphism specialized for lists:
xxapo :: ([a] -> Prim [a] (Either [a] [a])) -> [a] -> [a]
xxapo = apo
([a] -> Either [a] [a] vs [a] -> Prim [a] [a] (Either [a] [a])
So I wonder is it possible to implement filtering using apomorphisms or other generalized unfolds, or ana . para is the best I can hope for?
I know I can use folds, but the question is specifically about unfolds.
In short: This can't be done. You always have to break down the input list somehow, which you can't accomplish by unfolding alone. You can see that in your code already. You have retry (phi f), which is equivalent to dropWhile (not . f), which recursively consumes an input list. In your case, the recursion is inside retry.
We can implement filter using ana, but the function passed to ana will have to be recursive, as in
filter1 :: (a -> Bool) -> [a] -> [a]
filter1 p = ana f
where
f [] = Nil
f (x : xs') | p x = Cons x xs'
| otherwise = f xs'
However, we can implement filtering using para without any further recursion:
filter2 :: (a -> Bool) -> [a] -> [a]
filter2 p = cata f
where
f Nil = []
f (Cons x r) | p x = x : r
| otherwise = r
(although this is not what you've been interested in).
So why it works with cata but not with ana?
Catamorphisms represent inductive recursion where each recursive step consumes at least one constructor. Since each steps takes only finite time, together this ensures that when consuming a (finite) data structure, the whole recursion always terminates.
Anamorphisms represent co-inductive recursion where each recursive step is guarded by a constructor. This means that although the result can be infinite, each part (a constructor) of the constructed data structure is produced in finite time.
Now how filter works: At each step it consumes one element of a list and sometimes it produces an output element (if it satisfies a given predicate).
So we see that we can implement filter as a catamorphism - we consume each element of a list in a finite time.
But we can't implement filter just as an anamorphism. We can never know when filter produces a new result. We can't describe the production of a next output element using just a finite number of operations. For example, let's take filter odd (replicate n 0 ++ [1]) - it takes O(n) steps to produce the first element 1. So there must be some kind of recursion that searches an input list until it finds a satisfying element.
xfilter :: (a -> Bool) -> [a] -> [a]
xfilter f xs = last $ apo phi ([xs], []) where
phi ([[]], ys) = Cons [] $ Left [ys]
phi ([h:t], ys) | f h = Cons [] $ Right ([t], h:ys)
phi ([h:t], ys) = Cons [] $ Right ([t], ys)
But last is a cata.