I am curious about where getZipList is defined in ghc.
Control.Applicative has this definition for ZipList.
newtype ZipList a = ZipList { getZipList :: [a] }
One way to use ZipLists is (from LYAH):
ghci> getZipList $ (+) <$> ZipList [1,2,3] <*> ZipList [100,100,100]
[101,102,103]
I am curious how getZipList knows what to return.
Perhaps I am missing something about the newtype keyword.
Thanks!
It's not just newtype, it works the same with data. What you seem to be unaware of is named field syntax,
newtype ZipList a = ZipList { getZipList :: [a] }
is almost the same as
newtype ZipList a = ZipList [a]
getZipList :: ZipList a -> [a]
getZipList (ZipList xs) = xs
but the named field syntax allows more convenient updating and pattern matching - in particular it's much more convenient for named fields in data types with multiple fields.
The named field (implicitly) defines the accessor function that extracts the contained data from the wrapped value.
The secret is not in the newtype definition but in the applicative instance it has for <*>
instance Applicative ZipList where
pure x = ZipList (repeat x)
ZipList fs <*> ZipList xs = ZipList [f x | (f,x) <- zip fs xs]
The default list is like this instead, and that is where the difference comes from
instance Applicative [] where
pure x = [x]
fs <*> xs = [f x | f <- fs, x <- xs]
Related
I expect the following behavior from the applicative instance of my ZipList':
zipListApplyTest = fs <*> xs
where fs = ZipList' [negate, id]
xs = ZipList' [1..5]
-- Result: ZipList' [-1,2]
This was my first attempt:
newtype ZipList' a = ZipList' [a]
deriving (Eq, Show)
instance Functor ZipList' where
fmap f (ZipList' xs) = ZipList' $ fmap f xs
instance Applicative ZipList' where
pure x = ZipList' [x]
ZipList' (f:fs) <*> ZipList' (x:xs) =
ZipList' $ f x : (fs <*> xs) -- <-- the bug is here
ZipList' [] <*> _ = ZipList' []
_ <*> ZipList' [] = ZipList' []
-- Unexpected result: ZipList' [-1,2,3,4,5]
After some head scratching, I realized that inside the applicative instance of ZipList' I accidentally used the wrong <*>:
In the line marked with the bug is here, I applied the <*> that belongs to the built-in list type [] instead of applying <*> of ZipList' recursively.
This is why the second function id was applied to the entire rest of the list, instead of only the second element, 2.
This yielded the expected result:
ZipList' fs <*> ZipList' xs = ZipList' $ zipApply fs xs
where zipApply :: [(a -> b)] -> [a] -> [b]
zipApply (f:fs) (x:xs) = f x : zipApply fs xs
zipApply _ _ = []
Is there a compiler flag, language idiom, or other technique that would have prevented this bug or would have made it easier to spot?
I'm on GHC 8.2.2.
We can do this:
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
-- at very top of file ^
-- ...
-- pick whatever names/operators you want
-- synonym signatures are given in GADT-like syntax
-- ZCons decomposes a ZipList' a into an a and a ZipList' a
-- (assuming it succeeds). This is the syntax even for pattern synonyms that
-- can only be used as patterns
-- (e.g. pattern Fst :: a -> (a, b); pattern Fst a <- (a, _)).
pattern ZCons :: a -> ZipList' a -> ZipList' a
-- xs needs to be a ZipList', but it's only a [a], so we uglify this synonym
-- by using the newtype wrapper as a view
pattern ZCons x xs <- ZipList' (x:(ZipList' -> xs))
-- views aren't in general invertible, so we cannot make this an automatically
-- bidirectional synonym (like ZNil is). We can give an explicit version
where ZCons x (ZipList' xs) = ZipList' $ x:xs
-- simple enough that we can use one definition for both pattern and expression
pattern ZNil :: ZipList' a
pattern ZNil = ZipList' []
{-# COMPLETE ZNil, ZCons #-}
-- ZNil and ZCons cover all ZipLists
instance Applicative ZipList' where
pure x = ZipList' $ repeat x
-- these are bidirectional
(ZCons f fs) <*> (ZCons x xs) = ZCons (f x) (fs <*> xs)
_ <*> _ = ZNil
As a variant of AJFarmar's answer, you can keep your definition of ZipList' exploiting a [a] list inside, and instead declare pattern synonyms to pretend the type was declared as
data ZipList' a = ZipCons a (ZipList' a) | ZipNil
In that way, if you limit yourself in using these "pretend" constructors when you write your instances, you can not inadvertently involve a list.
{-# LANGUAGE PatternSynonyms, ViewPatterns #-}
{-# OPTIONS -Wall #-}
module ZipList where
newtype ZipList' a = ZipList' { unZipList' :: [a] }
deriving (Eq, Show)
Here are the pattern synonyms. We need to be a bit careful here since we need to convert lists to zip-lists as needed.
pattern ZipCons :: a -> ZipList' a -> ZipList' a
pattern ZipCons x xs <- ZipList' (x : (ZipList' -> xs))
where ZipCons x xs = ZipList' (x : unZipList' xs)
pattern ZipNil :: ZipList' a
pattern ZipNil = ZipList' []
We can leave the functor instance as it was, exploiting the Functor [] instance. Here, we do want to call the list fmap. Otherwise, we could use the "pretend" constructors, but we'd have to re-implement it.
instance Functor ZipList' where
fmap f (ZipList' xs) = ZipList' $ fmap f xs
Finally, the applicative instance can use only the pretend constructors.
instance Applicative ZipList' where
pure x = ZipCons x ZipNil
ZipCons f fs <*> ZipCons x xs = ZipCons (f x) (fs <*> xs)
_ <*> _ = ZipNil
To me a major downside of using the pattern synonyms is that the exhaustiveness checker gets easily confused, triggering spurious warnings. Above, if we replace the _ <*> _ case with the two obvious cases involving ZipNil, we trigger a warning.
(Update: HTNV used a COMPLETE pragma to silence the warning, which looks very nice! I did not know about that.)
Apart from that, pattern synonyms allow to offer a quite elegant interface. I wish they were used more often in the Haskell ecosystem.
No, you cannot prevent this in general. You must simply write your instances carefully.
That being said, one quick way to work around this problem would be to redefine your datatype; instead of putting it in terms of lists, make a new list type:
data Ziplist a = Nil | Cons a (Ziplist a)
-- (Instances etc follow)
This avoids the possibility for this kind of error. However, this isn't necessarily the best idea, since this requires function rewrites and so on.
You could just write tests. Which is best. So write tests. HSpec is the most used test framework as far as I'm aware, so that would be a good place to start.
This isn't really a general answer, but in this particular case I think by far the best and easiest thing is to just use zipWith, which is what the base library does.
instance Applicative ZipList where
pure x = ZipList (repeat x)
ZipList fs <*> ZipList xs = ZipList (zipWith ($) fs xs)
Haskell has Functor, Applicative and Monad instances defined for functions (specifically the partially applied type (->) a) in the standard library, built around function composition.
Understanding these instances is a nice mind-bender exercise, but my question here is about the practical uses of these instances. I'd be happy to hear about realistic scenarios where folks used these for some practical code.
A common pattern that involves Functor and Applicative instances of functions is for example (+) <$> (*2) <*> (subtract 1). This is particularly useful when you have to feed a series of function with a single value. In this case the above is equivalent to \x -> (x * 2) + (x - 1). While this is very close to LiftA2 you may extend this pattern indefinitely. If you have an f function to take 5 parameters like a -> a -> a -> a -> a -> b you may do like f <$> (+2) <*> (*2) <*> (+1) <*> (subtract 3) <*> (/2) and feed it with a single value. Just like in below case ;
Prelude> (,,,,) <$> (+2) <*> (*2) <*> (+1) <*> (subtract 3) <*> (/2) $ 10
(12.0,20.0,11.0,7.0,5.0)
Edit: Credit for a re-comment of #Will Ness for a comment of mine under another topic, here comes a beautiful usage of applicative over functions;
Prelude> let isAscending = and . (zipWith (<=) <*> drop 1)
Prelude> isAscending [1,2,3,4]
True
Prelude> isAscending [1,2,5,4]
False
Sometimes you want to treat functions of the form a -> m b (where m is an Applicative) as Applicatives themselves. This often happens when writing validators, or parsers.
One way to do this is to use Data.Functor.Compose, which piggybacks on the Applicative instances of (->) a and m to give an Applicative instance for the composition:
import Control.Applicative
import Data.Functor.Compose
type Star m a b = Compose ((->) a) m b
readPrompt :: Star IO String Int
readPrompt = Compose $ \prompt -> do
putStrLn $ prompt ++ ":"
readLn
main :: IO ()
main = do
r <- getCompose (liftA2 (,) readPrompt readPrompt) "write number"
print r
There are other ways, like creating your own newtype, or using ready-made newtypes from base or other libraries.
here an application of the bind function that I used for solving the Diamond Kata. Take a simple function that mirrors its input discarding the last element
mirror :: [a] -> [a]
mirror xs = xs ++ (reverse . init) xs
let's rewrite it a bit
mirror xs = (++) xs ((reverse . init) xs)
mirror xs = flip (++) ((reverse . init) xs) xs
mirror xs = (reverse . init >>= flip (++)) xs
mirror = reverse . init >>= flip (++)
Here is my complete implementation of this Kata: https://github.com/enolive/exercism/blob/master/haskell/diamond/src/Diamond.hs
For a List, why does right apply (*>) behave as repeating and appending the second argument n times, where n is the length of the first argument?
ghci> [1,2,3] *> [4,5]
[4,5,4,5,4,5]
The *> operator is defined, by default, as
xs *> ys = id <$ xs <*> ys
which in turn translates, by default, to
const id <$> xs <*> ys
That is, it replaces each element of xs with id to get xs' and then calculates xs' <*> ys. [] is a Monad instance, where (=<<) = concatMap. One of the laws of Applicative lays out the relationship between Applicative and Monad instances:
pure = return
fs <*> as = fs `ap` as = fs >>= \f -> as >>= \a -> f a
For lists, this is
fs <*> as = [f a | f <- fs, a <- as]
So *> for lists is ultimately determined by the Monad instance.
Note that there is another very sensible Applicative instance for lists, which is made available through a newtype in Control.Applicative:
newtype ZipList a = ZipList [a]
instance Applicative ZipList where
pure = repeat
(<*>) = zipWith ($)
ghci> :t pure []
pure [] :: Applicative f => f [a]
ghci> pure []
[]
ghci> :t []
[] :: [a]
ghci> fmap ((:) 2) (pure [])
[2]
ghci> fmap ((:) 2) ([])
[]
I would have thought replacing pure[] with [] in fmap ((:) 2) (pure []) would result in the same outcome.. who can explain the difference to me?
The type of pure is Applicative f => a -> f a so pure []
has type Applicative f => f [a]. You can specify f explicitly for different applicative types e.g.
pure [] :: Maybe [String] //Just []
pure [] :: IO [String] //displays '[]' in ghci
pure [] :: [[String]] //[[]]
The type of fmap ((:) 2) (pure []) is (Applicative f, Num a) => f [a]. Since Ghci runs in the IO monad, which is an Applicative, it chooses f to be IO, and displays the resulting list [2] which is what you see.
You can specify the applicative type directly to see a different result e.g.
fmap ((:) 2) (pure []) :: (Maybe [Int])
which is Just [2]
In fmap ((:) 2) ([]), there are no elements in the input list so you get an empty list.
Why would it be the same? They're different expressions.
Perhaps it simplifies things if we just look at lists. So, there's the empty list []. Its type can be anything with brackets around it, in particular also a nested list:
Prelude> [] :: [[Int]]
[]
But there's also another "empty nested list":
Prelude> [[]] :: [[Int]]
[[]]
This one isn't really empty though, it merely contains only the empty list. ([[],[],[],...] would also be possible). In fact, that would be the result of what you've tried, if done in the list applicative:
Prelude Control.Applicative> pure [] :: [[Int]]
[[]]
It is certainly not the same as the empty list,
Prelude> [[]] == []
False
In particular,
Prelude> (length [], length [[]])
(0,1)
And fmappming over an empty list never does anything, while fmapping over an empty-containing list will call the function with []: an easy way to see this is
Prelude Control.Applicative> fmap undefined []
[]
Prelude Control.Applicative> fmap undefined [[]]
[* Exception: Prelude.undefined
The real confusing thing about your trials is that ghci silently uses the IO monad.
There's also a subclass of Applicative for actual emptiness:
Prelude Control.Applicative> :i Alternative
class Applicative f => Alternative f where
empty :: f a
(<|>) :: f a -> f a -> f a
some :: f a -> f [a]
many :: f a -> f [a]
-- Defined in `Control.Applicative'
instance Alternative [] -- Defined in `Control.Applicative'
instance Alternative Maybe -- Defined in `Control.Applicative'
Suppose I want to add two lists in Haskell. What is the most usual way to do this?
Here's what I did:
addLists :: (Integral a) => [a] -> [a] -> [a]
addLists xs ys = map add $ zip xs ys
where add (x, y) = x+y
There is a zipWith library function that combines two lists by using a supplied function. It does exactly what you want here and you get:
addLists = zipWith (+)
This uses (+) to combine the elements of lists given as further arguments.
Applicative Functor style:
import Control.Applicative
addLists xs ys = getZipList $ (+) <$> ZipList xs <*> ZipList ys
Note that this is so ugly because there are two ways to make List an Applicative Functor. The first (and IMHO less useful) way is to take all combination, and that way became the "standard", so (+) <$> [1,2] <*> [30,40] is [31,41,32,42]. The other way is to zip the lists as we need here, but as you can have only one type class instance per type, we have to wrap the lists in ZipLists, and to unwrap the result using getZipList.
addLists xs ys = zipWith (+) xs ys