Last active
December 14, 2015 07:49
-
-
Save pasberth/5053052 to your computer and use it in GitHub Desktop.
Monad in Ruby
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
class MonadContext | |
def initialize(monad_methods) | |
@monad = nil | |
@monad_methods = monad_methods | |
end | |
def monad | |
@monad || raise("Monad doesn't exist") | |
end | |
def context(&block) | |
context = Context.new do |name, *args, &block| | |
ptr = [] | |
v = Bind.new { ptr.empty? ? raise("Result isn't got yet.") : ptr.first } | |
join(@monad_methods.send(name, *args)) | |
bind {|a| @monad_methods.unit(block.call(a)) } if block | |
bind {|a| ptr[0] = a; @monad_methods.unit(a) } | |
v | |
end | |
context.instance_eval(&block) | |
self | |
end | |
def bind(&f) | |
@monad = @monad_methods.bind(monad, f) | |
end | |
def join(m) | |
if @monad | |
@monad = @monad_methods.join(@monad, m) | |
else | |
@monad = m | |
end | |
end | |
class Context | |
def initialize(&callback) | |
@callback = callback | |
end | |
def method_missing(name, *args, &block) | |
@callback.call(name, *args, &block) | |
end | |
end | |
class Bind < BasicObject | |
private *instance_methods | |
private | |
def initialize(&fetch) | |
@fetch = fetch | |
end | |
def method_missing(name, *args, &block) | |
@result = @fetch.() unless defined? @result | |
@result.send(name, *args, &block) | |
end | |
end | |
end | |
module Monad | |
def unit(a) | |
fail | |
end | |
def bind(m, k) | |
fail | |
end | |
def join(m, k) | |
bind(m, ->(_) { k }) | |
end | |
end | |
module MonadState | |
include Monad | |
def get() | |
fail | |
end | |
def put() | |
fail | |
end | |
def modify(f) | |
Monad(self) { s = get(); put(f.(s)) } | |
end | |
def gets(f) | |
Monad(self) { s = get(); unit(f.(s)) } | |
end | |
end | |
class State | |
include Monad | |
include MonadState | |
def unit(a) | |
->(s) { [a, s] } | |
end | |
def bind(m, k) | |
->(s) { | |
(a, s_) = m.(s) | |
k.(a).(s_) | |
} | |
end | |
def get() | |
->(s) { [s, s] } | |
end | |
def put(s) | |
->(_) { [nil, s] } | |
end | |
end | |
def Monad(*args, &context) | |
MonadContext.new(*args).context(&context).monad | |
end | |
def State(&context) | |
MonadContext.new(State.new).context(&context).monad | |
end | |
state = State do | |
get { |x| puts x } | |
x = get { |x| x ** 2 } | |
put x | |
get { |x| puts x } | |
end | |
state.call(42) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
update で変わった。
というふうに作って
のように使う