Skip to content

Instantly share code, notes, and snippets.

@eiel
Last active August 1, 2018 00:40
Show Gist options
  • Save eiel/5302011 to your computer and use it in GitHub Desktop.
Save eiel/5302011 to your computer and use it in GitHub Desktop.
Ruby でモナドしてみる。
# >> を *
# >>= を bind
# return を self.new
# mplus を +
# mzero を self.zero
#
# に見立てて Maybe モナド書いてみた
# bind に渡す block で Maybe と書きたくないので第二引数に型情報を付加してみた。
class Monad
def *(m)
bind { m }
end
def join
bind { |r| r }
end
end
class Maybe < Monad
attr_reader :value
# return
def initialize(value)
@value = value
end
# >>=
def bind(&block)
if just?
ret = block.call @value, Maybe
raise '戻り値がモナドじゃないです' unless ret.is_a?(Maybe)
ret
else
Maybe.zero
end
end
def self.zero
Maybe.new(nil)
end
def self.map(&block)
proc do |r|
if r.just?
new block.call(r.value)
else
zero
end
end
end
def +(n)
if n.just?
n
else
self
end
end
def nothing?
value.nil?
end
def just?
not nothing?
end
def inspect
if just?
"Just #{value}"
else
"Nothing"
end
end
end
Maybe.new(1)
.bind { |value,monad| monad.new(value * 2) } # => Just 2
(Maybe.new(1) * Maybe.zero)
.bind { |value,monad| monad.new(value * 2) } # => Nothing
Maybe.map { |n| n*10 }.call Maybe.new(1) # => Just 10
Maybe.new(1) * Maybe.zero * Maybe.new(2) # => Nothing
Maybe.zero + Maybe.new(1) + Maybe.zero # => Just 1
Maybe.zero + Maybe.new(1) + Maybe.zero + Maybe.new(3) # => Just 3
Maybe.new(Maybe.new(1)).join # => Just 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment