Skip to content

Instantly share code, notes, and snippets.

@alskipp
Last active August 29, 2015 14:26
Show Gist options
  • Save alskipp/45f144a5e2d5d16c54ad to your computer and use it in GitHub Desktop.
Save alskipp/45f144a5e2d5d16c54ad to your computer and use it in GitHub Desktop.
Fear not the flatMapper
-- a function that accepts 2 monad args ‘containing’ number types and multiplies the ‘contents’
mult a b =
a >>= \x ->
b >>= \y -> return (x * y)
mult (Just 2) (Just 3)
-- Just 6
mult Nothing Nothing
-- Nothing
mult (Just 2) Nothing
-- Nothing
mult Nothing (Just 3)
-- Nothing
mult [2,3] [10,100]
-- [20,200,30,300]
mult [] []
-- []
mult [2,3] []
-- []
mult [] [10,100]
-- []
{- ** Translation to Swift terminology **
`>>=` is flatMap
`\x -> …` is a closure, equivalent to { x in … }
`Just` is the same as `.Some` in Swift Optionals
`Nothing` is the same as .None in Swift Optionals
`return` is a function that wraps the return value in the appropriate monad. For example:
If the function receives a List, the return value will be wrapped in a List
If the function receives a Maybe, the return value will be wrapped in a Maybe
** So, what's the point? **
The `mult` function will accept any 2 monads of the same type that `contain` number types and just work (Maybe, List, Either, etc).
This is very handy as you can pass Maybe values (Optional) and later decide to use a `Result` type instead,
the function will continue to work, despite the fact that you're passing in a different data type (it just has to be a monad).
-}
-- The function is more likely to be written using do-notation, which would look like:
mult a b = do x <- a
y <- b
return (x * y)
// The general case can't be expressed in Swift, therefore two versions of the function are required.
// Notice that the function implementations are identical apart from the type signature
func mult(a:Int?, _ b:Int?) -> Int? {
return a.flatMap { x in
b.flatMap { y in return x * y }
}
}
func mult(a:[Int], _ b:[Int]) -> [Int] {
return a.flatMap { x in
b.flatMap { y in return x * y }
}
}
mult(.Some(2), .Some(3)) // .Some(6)
mult(.None, .None) // .None
mult(.None, .Some(3)) // .None
mult(.Some(2), .None) // .None
mult([2,3], [10, 100]) // [20, 200, 30, 300]
mult([], []) // []
mult([], [10, 100]) // []
mult([2,3], []) // []
/*
Swift treats `Optional`s in a special way, you don't need to explicitly pass or return an Optional
from a function, this is managed ‘behind the scenes’. I've been explicit to make it clear the types
of the argument. For example, this would work `mult(2, 3)` the type checker would choose the Optional
version of the function and promote the `2` & `3` arguments to optionals.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment