Last active
August 29, 2015 14:11
-
-
Save akuraru/7dd7fe4932ea25e8826b to your computer and use it in GitHub Desktop.
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
// 鳥とバランス棒のシノニムを定義 | |
typealias Birds = Int | |
typealias Pole = (left: Birds, right: Birds) | |
// 左右に鳥が飛んできたことを表現 | |
func landLeft(n: Birds) -> Pole -> Pole { | |
return {p in (p.left + n, p.right)}; | |
} | |
func landRight(n: Birds) -> Pole -> Pole { | |
return {p in (p.left, p.right + n)}; | |
} | |
// 動作チェック | |
landLeft(2)((0, 0)) | |
landRight(1)((1, 2)) | |
landLeft(2)( landRight(1)( landLeft(1)((0, 0)))) | |
// 複数回鳥が飛んできた場合見づらいので演算子を定義 | |
infix operator => { | |
associativity left | |
} | |
func =><T, U>(t: T, f : T -> U) -> U { | |
return f(t) | |
} | |
(0, 0) => landLeft(1) => landRight(1) => landLeft(2) | |
// 今の実装だと失敗を表現できない | |
landLeft(10)((0, 3)) | |
// 途中で失敗しているがそのことがわからない | |
// 大量のif文を書くしかなくなる | |
(0, 0) => landLeft(1) => landRight(4) => landLeft(-1) => landRight(-2) | |
///////////////////// | |
// 失敗を表現する型を定義 | |
// 成功した場合、Successでラップして値を返す | |
// 失敗した場合、Failureを返す | |
enum Maybe<T>: Printable { | |
case Success(T) | |
case Failure | |
// 実行時の見やすさのために定義 | |
var description: String { | |
switch self { | |
case let .Success(v): return "Success(\(v))" | |
case .Failure: return "Failure" | |
} | |
} | |
} | |
// Maybe版の関数を定義 | |
func mLandLeft(n: Birds) -> Pole -> Maybe<Pole> { | |
return {p in | |
switch (p.left + n, p.right) { | |
case let (l, r) where abs(l - r) < 4: | |
return .Success((l, r)) | |
case _: | |
return .Failure | |
} | |
} | |
} | |
func mLandRight(n: Birds) -> Pole -> Maybe<Pole> { | |
return {p in | |
switch (p.left, p.right + n) { | |
case let (l, r) where abs(l - r) < 4: | |
return .Success((l, r)) | |
case _: | |
return .Failure | |
} | |
} | |
} | |
func p(v : Printable) { | |
println(v.description) | |
} | |
// 試しに実行してみる | |
mLandLeft(1)((1, 2)) => p | |
mLandLeft(10)((0, 3)) => p | |
println("") | |
// 前と同様に演算子を定義する | |
infix operator >=> { | |
associativity left | |
} | |
func >=><T, U>(t: Maybe<T>, f : T -> Maybe<U>) -> Maybe<U> { | |
switch t { | |
case let .Success(v): return f(v) | |
case .Failure: return .Failure | |
} | |
} | |
// すでにFailureの場合、Failureを返す | |
.Failure >=> mLandLeft(2) => p; | |
// すでにFailureの場合、Failureになる | |
.Success((0, 0)) >=> mLandLeft(1) >=> mLandRight(4) >=> mLandLeft(-1) >=> mLandRight(-2) => p; | |
//////////////////////// | |
// Optional版の関数の定義 | |
func oLandLeft(n: Birds) -> Pole -> Pole? { | |
return {p in | |
switch (p.left + n, p.right) { | |
case let (l, r) where abs(l - r) < 4: | |
return (l, r) | |
case _: | |
return nil | |
} | |
} | |
} | |
func oLandRight(n: Birds) -> Pole -> Pole? { | |
return {p in | |
switch (p.left, p.right + n) { | |
case let (l, r) where abs(l - r) < 4: | |
return (l, r) | |
case _: | |
return nil | |
} | |
} | |
} | |
// Optional版の演算子を定義 | |
infix operator >>= { | |
associativity left | |
} | |
func >>=<T, U>(t: T?, f : T -> U?) -> U? { | |
switch t { | |
case let .Some(v): return f(v) | |
case .None: return .None | |
} | |
} | |
nil >>= oLandLeft(2) | |
(0, 0) >>= oLandLeft(1) >>= oLandRight(4) | |
(0, 0) >>= oLandLeft(1) >>= oLandRight(4) >>= oLandLeft(-1) >>= oLandRight(-2) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment