I have two composed applicative functors Maybe [Integer] and want to combine them with <$>/<*> but I am stuck with applying the applicative operation. The following does not typecheck:
(<*>) (<*>) ((<$>) ((+) <$>) $ Just [1,2,3]) $ Just [4,5,6]
Expected result:
Just [5,6,7,6,7,8,7,8,9]
The functor part works, i.e. the intermediate value passed to <*> as the first argument is Just [Integer -> Integer]. I am used to S-expressions so I have a hard time with the Haskell syntax. I know of Compose but I am interested in the mere composition wihtout abstraction.
As Li-yao Xia said, using liftA2 makes it a lot less confusing.
But if you still what to see what it becomes in terms of the underlaying operations, we can expand the definition of liftA2:
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2 f x y = f <$> x <*> y
so the solution becomes
(liftA2 . liftA2) (+) (Just [1,2,3]) (Just [4,5,6])
= liftA2 (liftA2 (+)) (Just [1,2,3]) (Just [4,5,6])
= (\f x y -> f <$> x <*> y) ((\f x y -> f <$> x <*> y) (+)) (Just [1,2,3]) (Just [4,5,6])
= ((\f x y -> f <$> x <*> y) (+)) <$> Just [1,2,3] <*> Just [4,5,6]
= (\x y -> (+) <$> x <*> y) <$> Just [1,2,3] <*> Just [4,5,6]
Now, this is not in point free style like your example above, and I really don't think it's helpful to convert it into point free, but here's the output from http://pointfree.io:
((<*>) . ((+) <$>)) <$> Just [1, 2, 3] <*> Just [4, 5, 6]
we can see that this is the same by eta-expanding:
(<*>) . ((+) <$>)
= \x y -> ((<*>) . ((+) <$>)) x y
= \x y -> ((<*>) $ ((+) <$>) x) y
= \x y -> ((<*>) ((+) <$> x)) y
= \x y -> (<*>) ((+) <$> x) y
= \x y -> ((+) <$> x) <*> y
= \x y -> (+) <$> x <*> y
liftA2 might be less confusing for this than (<*>).
(+) :: Int -> Int -> Int
liftA2 (+) :: [Int] -> [Int] -> [Int]
liftA2 (liftA2 (+)) :: Maybe [Int] -> Maybe [Int] -> Maybe [Int]
liftA2 (liftA2 (+)) (Just [1,2,3]) (Just [4,5,6])
The composition of two Applicatives is always an Applicative (unlike the case for Monad).
We can use this to our advantage here with the Compose newtype from Data.Functor.Compose:
newtype Compose f g a = Compose { getCompose :: f (g a) }
It requires a bit of wrapping, but this kind of solution could be useful under the right circumstances:
example :: Maybe [Int]
example =
getCompose ((+) <$> Compose (Just [1,2,3]) <*> Compose (Just [4,5,6]))
One other way could be to use the ListT transformer. While it works just fine in this case, for some reason it's a depreciated transformer, marked in red with "Deprecated: This transformer is invalid on most monads".
import Control.Monad.Trans.List
doit :: (Int-> Int -> Int) -> Maybe [Int] -> Maybe [Int] -> Maybe [Int]
doit f mt1 mt2 = runListT $ f <$> (ListT mt1) <*> (ListT mt2)
λ> doit (+) (Just [1,2,3]) (Just [4,5,6])
Just [5,6,7,6,7,8,7,8,9]
Related
During my study of Typoclassopedia I encountered this proof, but I'm not sure if my proof is correct. The question is:
One might imagine a variant of the interchange law that says something about applying a pure function to an effectful argument. Using the above laws, prove that:
pure f <*> x = pure (flip ($)) <*> x <*> pure f
Where "above laws" points to Applicative Laws, briefly:
pure id <*> v = v -- identity law
pure f <*> pure x = pure (f x) -- homomorphism
u <*> pure y = pure ($ y) <*> u -- interchange
u <*> (v <*> w) = pure (.) <*> u <*> v <*> w -- composition
My proof is as follows:
pure f <*> x = pure (($) f) <*> x -- identical
pure f <*> x = pure ($) <*> pure f <*> x -- homomorphism
pure f <*> x = pure (flip ($)) <*> x <*> pure f -- flip arguments
The first two steps of your proof look fine, but the last step doesn't. While the definition of flip allows you to use a law like:
f a b = flip f b a
that doesn't mean:
pure f <*> a <*> b = pure (flip f) <*> b <*> a
In fact, this is false in general. Compare the output of these two lines:
pure (+) <*> [1,2,3] <*> [4,5]
pure (flip (+)) <*> [4,5] <*> [1,2,3]
If you want a hint, you are going to need to use the original interchange law at some point to prove this variant.
In fact, I found I had to use the homomorphism, interchange, and composition laws to prove this, and part of the proof was pretty tricky, especially getting the sections right --like ($ f), which is different from (($) f). It was helpful to have GHCi open to double-check that each step of my proof type checked and gave the right result. (Your proof above type checks fine; it's just that the last step wasn't justified.)
> let f = sqrt
> let x = [1,4,9]
> pure f <*> x
[1.0,2.0,3.0]
> pure (flip ($)) <*> x <*> pure f
[1.0,2.0,3.0]
>
I ended up proving it backwards:
pure (flip ($)) <*> x <*> pure f
= (pure (flip ($)) <*> x) <*> pure f -- <*> is left-associative
= pure ($ f) <*> (pure (flip ($)) <*> x) -- interchange
= pure (.) <*> pure ($ f) <*> pure (flip ($)) <*> x -- composition
= pure (($ f) . (flip ($))) <*> x -- homomorphism
= pure (flip ($) f . flip ($)) <*> x -- identical
= pure f <*> x
Explanation of the last transformation:
flip ($) has type a -> (a -> c) -> c, intuitively, it first takes an argument of type a, then a function that accepts that argument, and in the end it calls the function with the first argument. So flip ($) 5 takes as argument a function which gets called with 5 as it's argument. If we pass (+ 2) to flip ($) 5, we get flip ($) 5 (+2) which is equivalent to the expression (+2) $ 5, evaluating to 7.
flip ($) f is equivalent to \x -> x $ f, that means, it takes as input a function and calls it with the function f as argument.
The composition of these functions works like this: First flip ($) takes x as it's first argument, and returns a function flip ($) x, this function is awaiting a function as it's last argument, which will be called with x as it's argument. Now this function flip ($) x is passed to flip ($) f, or to write it's equivalent (\x -> x $ f) (flip ($) x), this results in the expression (flip ($) x) f, which is equivalent to f $ x.
You can check the type of flip ($) f . flip ($) is something like this (depending on your function f):
λ: let f = sqrt
λ: :t (flip ($) f) . (flip ($))
(flip ($) f) . (flip ($)) :: Floating c => c -> c
I'd remark that such theorems are, as a rule, a lot less involved when written in mathematical style of a monoidal functor, rather than the applicative version, i.e. with the equivalent class
class Functor f => Monoidal f where
pure :: a -> f a
(⑂) :: f a -> f b -> f (a,b)
Then the laws are
id <$> v = v
f <$> (g <$> v) = f . g <$> v
f <$> pure x = pure (f x)
x ⑂ pure y = fmap (,y) x
a⑂(b⑂c) = assoc <$> (a⑂b)⑂c
where assoc ((x,y),z) = (x,(y,z)).
The theorem then reads
pure u ⑂ x = swap <$> x ⑂ pure u
Proof:
swap <$> x ⑂ pure u
= swap <$> fmap (,u) x
= swap . (,u) <$> x
= (u,) <$> x
= pure u ⑂ x
□
I'm just looking to make general improvements to my Haskell code, and was wondering if the following function could be made point-free? Mostly for curiosity's sake.
Given two functions which we'd like to use in our filter:
isZero = (==0)
isOne = (==1)
How would we go about utilising those two functions in our contrived example, but making it point-free?
filter (\x -> isZero x || isOne x) [0..100]
There's a online-service for converting Haskell code to point-free.
It suggests: filter (liftM2 (||) isZero isOne) [0..100]
liftA2 (||) isZero isOne or (||) <$> isZero <*> isOne is also possible
(||) <$> isZero has type a0 -> Bool -> Bool and it's the composition of (||) and isZero. This composition takes a number (for isZero) and a boolean (as another argument for (||))
So, it's the same as \x y -> (||) (isZero x) y
The function type is an instance of Applicative Functor and we can look at its implementation:
instance Applicative ((->) r) where
pure x = (\_ -> x)
f <*> g = \x -> f x (g x)
So, (||) <$> isZero <*> isOne is the same as \x -> ((||) <$> isZero) x (isOne x) and the same as \x -> (||) (isZero x) (isOne x)
Thus, if there's z x = y (f x) (g x), it can be transformed into point free: z = y <$> f <*> g
An alternate point-free form would be to use the a -> Any monoid:
λ import Data.Monoid (Any(..))
λ :t getAny . (Any . isZero <> Any . isOne)
getAny . (Any . isZero <> Any . isOne)
:: (Num a, Eq a) => a -> Bool
λ filter (getAny . (Any . isZero <> Any . isOne)) [0..100]
[0,1]
It's a bit longer than the Applicative solution, but I think it's a little easier to follow when you have more conditions to combine. Compare
getAny . (Any . isZero <> Any . isOne <> Any . isSquare <> Any . isPrime)
or
getAny . foldMap (Any .) [isZero, isOne, isSquare, isPrime]
and
liftA2 (||) (liftA2 (||) (liftA2 (||) isZero isOne) isSquare) isPrime
or
liftA2 (||) isZero $ liftA2 (||) isOne $ liftA2 (||) isSquare isPrime
Though to be honest, if I had lots of these to do, I'd be tempted to define <||> = liftA2 (||) and do
isZero <||> isOne <||> isSquare <||> isPrime
Consider the following function:
foo =
[1,2,3] >>=
return . (*2) . (+1)
For better readability and logic, I would like to move my pure functions (*2) and (+1) to the left of the return. I could achieve this like this:
infixr 9 <.
(<.) :: (a -> b) -> (b -> c) -> (a -> c)
(<.) f g = g . f
bar =
[1,2,3] >>=
(+1) <.
(*2) <.
return
However, I don't like the right-associativity of (<.).
Let's introduce a function leftLift:
leftLift :: Monad m => (a -> b) -> a -> m b
leftLift f = return . f
baz =
[1,2,3] >>=
leftLift (+1) >>=
leftLift (*2) >>=
return
I quite like this. Another possibility would be to define a variant of bind:
infixl 1 >>$
(>>$) :: Monad m => m a -> (a -> b) -> m b
(>>$) m f = m >>= return . f
qux =
[1,2,3] >>$
(+1) >>$
(*2) >>=
return
I am not sure whether that is a good idea, since it would not allow me to use do notation should I want that. leftLift I can use with do:
bazDo = do
x <- [1,2,3]
y <- leftLift (+1) x
z <- leftLift (*2) y
return z
I didn't find a function on Hoogle with the signature of leftLift. Does such a function exist, and, if, what is it called? If not, what should I call it? And what would be the most idiomatic way of doing what I am trying to do?
Edit: Here's a version inspired by #dunlop's answer below:
infixl 4 <&>
(<&>) :: Functor f => f a -> (a -> b) -> f b
(<&>) = flip fmap
blah =
[1,2,3] <&>
(+1) <&>
(*2) >>=
return
I should also add that I was after a bind-variant, because I wanted to write my code in point-free style. For do-notation, I guess I don't need to "pretend" that I'm doing anything monadic, so I can use lets.
Every Monad is a Functor (and an Applicative too). Your (>>$) is (flipped) fmap.
GHCi> :t fmap
fmap :: Functor f => (a -> b) -> f a -> f b
GHCi> :t (<$>) -- Infix synonym for 'fmap'
(<$>) -- Infix synonym for 'fmap'
:: Functor f => (a -> b) -> f a -> f b
GHCi> fmap ((*2) . (+1)) [1,2,3]
[4,6,8]
GHCi> (*2) . (+1) <$> ([1,2,3] >>= \x -> [1..x])
[4,4,6,4,6,8]
(By the way, a common name for flipped fmap is (<&>). That is, for instance, what lens calls it.)
If you are using do-notation, there is little reason to use any variant of fmap explicitly for this kind of transformation. Just switch your <- monadic bindings for let-bindings:
bazDo = do
x <- [1,2,3]
let y = (+1) x
z = (*2) y
return z
bazDo = do
x <- [1,2,3]
let y = (+1) x
return ((*2) z)
For better readability...
That's going to be subjective as people disagree on what constitutes readable.
That being said, I agree that sometimes it's easier to understand data transformations when they are written left to right. I think your >>$ is overkill, though. The & operator in Data.Function does the job:
import Data.Function
foo = [1,2,3] & fmap (+1) & fmap (*2)
I like that this says exactly what to start with and exactly what to do at each step from left to right. And unlike >>$, you aren't forced to remain in the monad:
bar = [1,2,3] & fmap (+1) & fmap (*2) & sum & negate
Or you can just assemble your transformation beforehand and map it over your monad:
import Control.Category
f = (+1) >>> (*2)
quuz = fmap f [1,2,3]
Two examples both from http://learnyouahaskell.com/functors-applicative-functors-and-monoids#applicative-functors,
1). (+) <$> (+3) <*> (*100) $ 5
(+) <$> (+3) <*> (*100) $ 5, the 5 first got applied to (+3) and
(*100), resulting in 8 and 500. Then, + gets called with 8 and 500,
resulting in 508.
From the first example, it seems like <*> has higher precedence than <$>.
2). (++) <$> Just "johntra" <*> Just "volta"
(++) <$> Just "johntra" <*> Just "volta", resulting in a value
that's the same as Just ("johntra"++),and now Just ("johntra"++) <*>
Just "volta" happens, resulting in Just "johntravolta".
From the second example, it seems like <$> has higher precedence than <*>.
So do they have the same precedence? can someone give me some explanations/references?
indeed they both have the same precedence (infixl 4: (<*>) and (<$>)) and you can just read it from left to right -
(+) <$> (+3) <*> (*100) $ 5
= ((+) <$> (+3)) <*> (*100) $ 5
= (\ a b -> (a+3) + b) <*> (\ a -> a*100) $ 5
= (\ a -> (a+3) + (a*100)) $ 5
= 8 + 500 = 508
remember in this case we have f <*> g = \x -> f x (g x)
<$> and <*> has same precedence and left associativity. $ has the lowest precedence of zero. You can use ghci to explore information about them:
λ> :i (<$>)
(<$>) :: Functor f => (a -> b) -> f a -> f b
-- Defined in ‘Data.Functor’
infixl 4 <$>
λ> :i (<*>)
class Functor f => Applicative (f :: * -> *) where
...
(<*>) :: f (a -> b) -> f a -> f b
...
-- Defined in ‘Control.Applicative’
infixl 4 <*>
Now you can work out the types to see how they typecheck.
When I don't grasp how an expression in Haskell works I often find it helps to decompose it into a more basic form.
Using the following definitions
sequenceA :: (Applicative f) => [f a] -> f [a]
sequenceA [] = pure []
sequenceA (x:xs) = (:) <$> x <*> sequenceA xs
instance Applicative ((->) r) where
pure x = (\_ -> x)
f <*> g = \x -> f x (g x)
I rewrote sequenceA [(+3),(+2)] 3 as
(\_ -> (:)) <*> (+3) <*> ((\_ -> (:)) <*> (+2) <*> (\_-> [])) $ 3
And then turned it into (please excuse the format; I'm not sure what the convention is for splitting lines)
(\d ->(\c->(\b -> (\a -> (\_ -> (:)) a (+3) a) b (\_ -> (:)) b) c (+2) c) d (\_ -> []) d) 3
This seems right when I work through it by hand, but I can't get GHCi to accept it. What have I done wrong here? My second question is how to convert from this form into functional composition. I've tried substituing dots in various combinations, but GHCi rejects all of them....
Being an idle goodfornothing, I thought I would make a computer do the expansion for me. So into GHCi, I typed
let pu x = "(\\_ -> " ++ x ++ ")"
let f >*< a = "(\\g -> " ++ f ++ " g (" ++ a ++ " g))"
So now I have funny versions of pure and <*> which map strings which look like expressions to string which look like more complicated expressions. I then defined, similarly, the analogue of sequenceA, replacing functions by strings.
let sqa [] = pu "[]" ; sqa (f : fs) = (pu "(:)" >*< f) >*< sqa fs
I was then able to generate the expanded form of the example as follows
putStrLn $ sqa ["(+3)","(+2)"] ++ " 3"
which duly printed
(\g -> (\g -> (\_ -> (:)) g ((+3) g)) g ((\g -> (\g -> (\_ -> (:)) g ((+2) g)) g ((\_ -> []) g)) g)) 3
This last, copied to the prompt, yielded
[6,5]
Comparing the output from my "metaprogram" with the attempt in the question shows a shorter initial prefix of lambdas, arising from a shallower nesting of <*> operations. Remember, it's
(pure (:) <*> (+3)) <*> ((pure (:) <*> (+2)) <*> pure [])
so the outer (:) should be only three lambdas deep. I suspect the proposed expansion may correspond to a differently bracketed version of the above, perhaps
pure (:) <*> (+3) <*> pure (:) <*> (+2) <*> pure []
Indeed, when I evaluate
putStrLn $ pu "(:)" >*< "(+3)" >*< pu "(:)" >*< "(+2)" >*< pu "[]" ++ " 3 "
I get
(\g -> (\g -> (\g -> (\g -> (\_ -> (:)) g ((+3) g)) g ((\_ -> (:)) g)) g ((+2) g)) g ((\_ -> []) g)) 3
which looks like it matches the (updated)
(\d -> (\c -> (\b -> (\a -> (\_ -> (:)) a ((+3) a)) b ((\_ -> (:)) b)) c ((+2) c)) d ((\_ -> []) d)) 3
I hope this machine-assisted investigation helps to clarify what's going on.
You rewrote (\_ -> (:)) <*> (+3) as \a -> (\_ -> (:)) a (+3) a, which is rewriting f <*> g as f x g x instead of f x (g x). I think you made that mistake for every <*>.
It might be easier to use combinators, e.g. _S and _K, symbolically, and not their definitions as lambda-expressions,
_S f g x = f x (g x)
_K x y = x
With functions, fmap is (.) and <*> is _S, as others already mentioned. So,
sequenceA [(+3),(+2)] 3 ==
( ((:) <$> (+3)) <*> sequenceA [(+2)] ) 3 ==
_S ((:).(+3)) ( ((:) <$> (+2)) <*> pure [] ) 3 ==
_S ((:).(+3)) ( _S ((:).(+2)) (_K []) ) 3 ==
((:).(+3)) 3 ( _S ((:).(+2)) (_K []) 3 ) ==
((:).(+3)) 3 ( ((:).(+2)) 3 (_K [] 3) ) ==
(6:) ( (5:) [] ) ==
[6,5]
So it might be easier to decompose expressions down to basic functions and combinators and stop there (i.e. not decomposing them to their lambda expressions), using their "re-write rules" in manipulating the expression to find its more comprehensible form.
If you wanted to, you could now write down for yourself a more abstract, informal re-write rule for sequenceA as
sequenceA [f,g,..., z] ==
_S ((:).f) . _S ((:).g) . _S ..... . _S ((:).z) . _K []
and so
sequenceA [f,g,..., z] a ==
((:).f) a $ ((:).g) a $ ..... $ ((:).z) a $ _K [] a ==
(f a:) $ (g a:) $ ..... $ (z a:) $ [] ==
[f a, g a, ..., z a]
and hence
sequenceA fs a == map ($ a) fs == flip (map . flip ($)) fs a
to wit,
Prelude Control.Applicative> flip (map . flip ($)) [(+3),(+2)] 3
[6,5]