Skip to content

Instantly share code, notes, and snippets.

@alskipp
Last active November 14, 2015 09:10
Show Gist options
  • Save alskipp/c408e8954af4beb8861b to your computer and use it in GitHub Desktop.
Save alskipp/c408e8954af4beb8861b to your computer and use it in GitHub Desktop.
Powerset function in Swift using filterM
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