Skip to content

Instantly share code, notes, and snippets.

@ericgj
Created December 2, 2015 22:39
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 ericgj/e56c37d3f979494085a2 to your computer and use it in GitHub Desktop.
Save ericgj/e56c37d3f979494085a2 to your computer and use it in GitHub Desktop.
# More or less direct translation of folktale.js data.task + control.async.parallel
# https://github.com/folktale/data.task/blob/master/lib/task.js
# https://github.com/folktale/control.async/blob/master/lib/core.js
module Monads
class Task
def self.of(x)
new {|_,res| res[x] }
end
# Note: not actually executed in parallel (async)
def self.parallel(tasks)
Task.new do |rej, res|
len = tasks.length
result = Array.new(len)
resolved = false
runComputation = ->(t,i){
t.fork[
->(e){
return if resolved
resolved = true
rej[e]
},
->(v){
return if resolved
result[i] = v
len -= 1
if len == 0
resolved = true
res[result]
end
}
]
}
if len == 0
res[[]]
else
tasks.each_with_index(&runComputation)
end
end
end
attr_reader :fork
def initialize(&fork)
@fork = fork
end
def map(&f)
Task.new do |rej, res|
fork[ -> (a) { rej[a] }, -> (b) { res[f[b]] } ]
end
end
def chain(&f)
Task.new do |rej, res|
fork[ -> (a) { rej[a] }, -> (b) { f[b].fork[rej, res] } ]
end
end
def ap(other)
chain { |f| other.map(&f) }
end
end
end
if __FILE__ == $0
readFile = -> (f) {
Monads::Task.new { |rej,res| File.open(f){ |io| res[[f, io.read]] } }
}
tasks = Dir['./*.rb'].map {|f| readFile[f].map {|name, str| [name, str.length] } }
seq = Monads::Task.parallel(tasks)
seq.fork[ -> (err){}, -> (pairs){ puts Hash[pairs] } ]
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment