Last active
November 14, 2015 09:10
-
-
Save alskipp/c408e8954af4beb8861b to your computer and use it in GitHub Desktop.
Powerset function in Swift using filterM
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
func pure<A>(x:A) -> [A] { | |
return [x] | |
} | |
func filterM<A>(xs:[A], predicate: A -> [Bool]) -> [[A]] { | |
return reduce(xs, pure([])) { acc, x in | |
predicate(x).flatMap { b in b ? (acc.flatMap { pure($0 + [x]) }) : acc } | |
} | |
} | |
filterM([1,2,3]) { x in [true, false] } | |
// result> [[1, 2, 3], [2, 3], [1, 3], [3], [1, 2], [2], [1], []] | |
filterM([1,2,3,4]) { x in [true, false] } | |
// result> [[1, 2, 3, 4], [2, 3, 4], [1, 3, 4], [3, 4], [1, 2, 4], [2, 4], [1, 4], [4], [1, 2, 3], [2, 3], [1, 3], [3], [1, 2], [2], [1], []] | |
/* | |
Why use the function `pure`? | |
The `pure` function takes a value and places it within a simple context. | |
(In this instance, it's an Array – | |
A `pure` function for Optionals would return a simple value wrapped in an Optional). | |
By using the `pure` function it shows that `filterM`, can in theory be made completely general. | |
The implementation of `filterM` only uses functions available to monadic values (flatMap & pure), | |
therefore, the implementation for any monadic type is identical. | |
However, it's not yet possible in Swift to inform a function that the parameters or return value will be monadic. | |
Consequently, the function needs to be reimplemented for every additional type :( | |
The `pure` function takes the place of the `return` function in Haskell. | |
As `return` is a keyword in Swift, it's not possible to define a function with that name. | |
`pure` is used for the same purpose for Applicative types in Haskell, hence the choice of name here. | |
* * * | |
Below is the `filterM` function for Optionals. | |
Note that the only difference is the type parameters and return type of the function, | |
the implementation is identical. | |
*/ | |
func pure<A>(x:A) -> A? { | |
return .Some(x) | |
} | |
func filterM<A>(xs:[A], predicate: A -> Bool?) -> [A]? { | |
return reduce(xs, pure([])) { acc, x in | |
predicate(x).flatMap { b in b ? (acc.flatMap { pure($0 + [x]) }) : acc } | |
} | |
} | |
/* | |
The behaviour of `filterM` for Optionals is obviously different. | |
It allows you to filter an Array based upon a predicate, or to return failure (.None). | |
Here's an example of filtering an Array to include only even numbers, | |
but to fail if the Array contains any negative values. | |
*/ | |
filterM([1,2,3,4]) { x in x < 0 ? .None : .Some( x % 2 == 0 ) } | |
// result> .Some([2, 4]) | |
filterM([-1,0,1,2,3,4]) { x in x < 0 ? .None : .Some( x % 2 == 0 ) } | |
// result> .None |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment