Created
November 27, 2017 22:23
-
-
Save KyNorthstar/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 contains hidden or 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
/// 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