Skip to content

Instantly share code, notes, and snippets.

@KyLeggiero
Created November 27, 2017 22:23
Show Gist options
  • Save KyLeggiero/35a3db0c3cab3a84a2679498ea858417 to your computer and use it in GitHub Desktop.
Save KyLeggiero/35a3db0c3cab3a84a2679498ea858417 to your computer and use it in GitHub Desktop.
This file is an illustration of the concepts described in the Computerphile video "What is a Monad?", but in Swift rather than the video's Haskell. https://www.youtube.com/watch?v=t1e8gqXLbsU
/// This file is an illustration of the concepts described in the Computerphile video "What is a Monad?", but in Swift rather than the video's Haskell.
/// https://www.youtube.com/watch?v=t1e8gqXLbsU
import Cocoa
// MARK: - Stuff we need in order to make our code look like the code in the video
/// Our own private implementation of Haskell's do function. Note that this is less powerful because it just deals in `Int`s, but that's OK because this is only for this example.
private func `do`(_ n: @autoclosure () -> (Optional<Int>), _ m: @autoclosure () -> (Optional<Int>), action: (Int, Int) -> Optional<Int>) -> Optional<Int> {
return n() >>= { n in
m() >>= { m in
action(n, m) }}
}
private typealias Maybe<T> = Optional<T>
// MARK: - Just stuff in the video
indirect enum Expr {
case Val(Int)
case Div(Expr, Expr)
}
let example_1: Expr = .Val(1)
let example_2: Expr = .Div(.Val(6), .Val(2))
let example_3: Expr = .Div(.Val(6), .Div(.Val(3), .Val(1)))
func eval_1(_ expr: Expr) -> Int {
switch expr {
case .Val(let n): return n
case .Div(let x, let y): return eval_1(x) / eval_1(y)
}
}
func safediv(_ n: Int, _ m: Int) -> Maybe<Int> {
if m == 0 {
return .none
}
else {
return .some(n / m)
}
}
func eval_2(_ expr: Expr) -> Maybe<Int> {
switch expr {
case .Val(let n): return .some(n)
case .Div(let x, let y):
switch eval_2(x) {
case .none: return .none
case .some(let n):
switch eval_2(y) {
case .none: return .none
case .some(let m): return safediv(n, m)
}
}
}
}
infix operator >>= : ComparisonPrecedence
func >>=(m: Maybe<Int>, f: (Int) -> Maybe<Int>) -> Maybe<Int> {
switch m {
case .none: return .none
case .some(let x): return f(x)
}
}
func eval_3(_ expr: Expr) -> Maybe<Int> {
switch expr {
case .Val(let n): return n
case .Div(let x, let y): return eval_3(x) >>= { n in
eval_3(y) >>= { m in
safediv(n, m) }}
}
}
func eval_4(_ expr: Expr) -> Maybe<Int> {
switch expr {
case .Val(let n): return n
case .Div(let x, let y): return `do`(
eval_4(x),
eval_4(y)) { n, m in
safediv(n, m) }
}
}
// MARK: - Showing off the behavior of these
let example_4: Expr = .Div(.Val(2), .Val(0))
print(eval_1(example_1))
print(eval_1(example_2))
print(eval_1(example_3))
//print(eval_1(example_4)) // Uncomment to see CRASH
print(eval_2(example_1))
print(eval_2(example_2))
print(eval_2(example_3))
print(eval_2(example_4))
print(eval_3(example_1))
print(eval_3(example_2))
print(eval_3(example_3))
print(eval_3(example_4))
print(eval_4(example_1))
print(eval_4(example_2))
print(eval_4(example_3))
print(eval_4(example_4))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment