Skip to content

Instantly share code, notes, and snippets.

@akuraru
Last active August 29, 2015 14:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save akuraru/7dd7fe4932ea25e8826b to your computer and use it in GitHub Desktop.
Save akuraru/7dd7fe4932ea25e8826b to your computer and use it in GitHub Desktop.
// 鳥とバランス棒のシノニムを定義
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