Last active
August 29, 2015 14:26
-
-
Save alskipp/45f144a5e2d5d16c54ad to your computer and use it in GitHub Desktop.
Fear not the flatMapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- 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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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