2014-03-08 - [ type-tetris, haskell ]

Today I'm going to play with Alternatives.

(spoiler: I failed to understand what some and many do, and I guess that would be an essential part of getting Alternative. So there's not much thing useful in this article.)

Just as my other type-tetris attempts, this is not a tutorial about Alternative, I'll just provide some examples and intuitions gained throughout playing with it.

I happened to heard this typeclass by a quick scan on typeclassopedia, and there are only few functions related to it, which I think might not take much time to try them all. These are all motivations about this article.

As always, bold sentences stands for my intuitions.

“a monoid on applicative functors”

Alternative is a typeclass lied in Control.Applicative, most of the time, I import this package to use functions like <$>, <*> and data type ZipList, but no more. I happened to heard this typeclass by a quick scan on typeclassopedia, and there are only few functions related to it, which I think might not take much time to try them all. These are all motivations about this article.

import Control.Applicative

First function in this class is called empty, so I guess Alternative is some typeclass that allows containing nothing. This would explain why there are so many Applicatives but I can only see [] and Maybe being instances of this typeclass.

The document says Alternative is “a monoid on applicative functors”. So we can make an analogy between (mempty, mappend) from Monoid and (empty, <|>) from Alternative. Let's try it out:

v1 :: [String]
v1 = empty <|> empty <|> empty

v2 :: [String]
v2 = v1 <|> pure "foo" <|> pure "bar"

v3 :: Maybe Int
v3 = pure 10 <|> pure 20

v4 :: Maybe Char
v4 = empty <|> pure 'A' <|> undefined

v5 :: Maybe ()
v5 = empty <|> empty <|> empty

Let's bring up GHCi:

λ> v1
[]
λ> v2
["foo","bar"]
λ> v3
Just 10
λ> v4
Just 'A'
λ> v5
Nothing

empty works like what we expected, and <|> for lists seems straightforward. But when it comes to Maybe, we find that only the first non-Nothing one takes effect, if any.

some and many

The type for some and many are identical, so just fill in some instances I come up with on the fly:

v6 :: [[String]]
v6 = some ["not working"]

v7 :: [[String]]
v7 = some empty

But when I try this out on GHCi, something is going wrong:

λ> v6
^CInterrupted.
λ> v7
[]

I gave v6 some time to run but it didn't terminate, so I cancelled it by hand.

By looking at the document, I find some clue: some and many seem to look for some solutions to the following equations:

some v = (:) <$> v <*> many v
many v = some v <|> pure []

-- rewrite to break the recursive relation will help?
some v = (:) <$> v <*> (some v <|> pure [])
many v = ((:) ($) v <*> many v) <|> pure []

I can't go any further from here, but doing some research, I find the following links that might help, but for now I just leave this two functions as mysteries. (Maybe it's just something like fix, interesting, but IMHO not useful ).

Related links:

optional

For the rest of the story, I'll just type them directly into GHCi.

The last function about Alternative is optional, Let's check its type and feed it with some instances:

λ> :t optional
optional :: Alternative f => f a -> f (Maybe a)
λ> optional Nothing
Just Nothing
λ> optional $ Just 1
Just (Just 1)
λ> optional []
[Nothing]
λ> optional [1,2,3]
[Just 1,Just 2,Just 3,Nothing]

Wait a minute, is f a -> f (Maybe a) looks familiar to you? It looks like an unary function that has type a -> Maybe a under some contexts. I think the simplest expression that matches this type would be (Just <$>). Let's do the same thing on it.

λ> :t (Just <$>)
(Just <$>) :: Functor f => f a -> f (Maybe a)
λ> (Just <$>) Nothing
Nothing
λ> (Just <$>) Just 1
Just (Just 1)
λ> (Just <$>) []
[]
λ> (Just <$>) [1,2,3]
[Just 1,Just 2,Just 3]

Comparing the output of optional and (Just <$>), we find that optional will attach an empty to the end of this monoid. And that empty would be the “none” part from optional's description: “One or none”. In addition, we've seen <|> is the binary operation for this monoid, so we can have a guess:

optional v = (Just <$> v) <|> pure Nothing

And this turns out to be the exact implementation.

Summary

Not much is done in this post, I have to admit that type-tetris is not always the best way. As an afterthought, I didn't know how Alternative will be used so there was little hint that I can rely on when I was trying to figure out many and some.

Anyway, if happened to read all contents in this article, sorry for wasting your time and thanks for your patience.



comments powered by Disqus