Module: Fr::Monad
- Includes:
- Functor
- Defined in:
- lib/fr/monad.rb
Instance Method Summary collapse
-
#applyM(mf, ma = nil) ⇒ Object
-
Monad m => m (a -> b) -> m a -> m b.
-
#composeM(f, g = nil, &block) ⇒ Object
- Left-to-right Kleisli composition of monads
-
Monad m => (a -> m b) -> (b -> m c) -> a -> m c.
-
#filterM(f, as = nil) ⇒ Object
-
Monad m => (a -> m Boolean) -> [a] -> m [a].
-
#foldM(f, seed = nil, bs = nil) ⇒ Object
-
Monad m => (a -> b -> m a) -> a -> [b] -> m a.
-
#forM(as, f = nil, &block) ⇒ Object
-
Monad m => [a] -> (a -> m b) -> m [b].
-
#join(mm) ⇒ Object
- Remove one level of monadic structure
-
Monad m => m (m a) -> m a.
-
#liftM(f = nil, ma = nil, &block) ⇒ Object
(also: #map)
-
Monad m => (a -> b) -> m a -> m b.
-
#mapM(f, as = nil) ⇒ Object
-
Monad m => (a -> m b) -> [a] -> m [b].
-
#sequence(ms) ⇒ Object
- Perform each action, from left to right
-
Monad m => [m a] -> m [a].
-
#unlessM(condition) ⇒ Object
-
Monad m => Bool -> m () -> m ().
-
#whenM(condition) ⇒ Object
-
Monad m => Bool -> m () -> m ().
-
#zipM(f, xs = nil, ys = nil) ⇒ Object
-
Monad m => (a -> b -> m c) -> [a] -> [b] -> m [c].
Methods included from Functor
Instance Method Details
#applyM(mf, ma = nil) ⇒ Object
-
Monad m => m (a -> b) -> m a -> m b
>> mf = m.unit(lambda{|x| lambda{|y| x + y }})
>> ab = m.applyM(mf) >> ma = m.applyM(ab.call(m.unit 3)) >> mb = ma.call(m.unit 4)
> m.unit(7)
221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/fr/monad.rb', line 221 def applyM(mf, ma = nil) rest = lambda do |ma| bind(mf) do |f| bind(ma) do |a| unit(f.call(a)) end end end (ma.nil?) ? rest : rest.call(ma) end |
#composeM(f, g = nil, &block) ⇒ Object
Left-to-right Kleisli composition of monads
-
Monad m => (a -> m b) -> (b -> m c) -> a -> m c
>> m.composeM(lambda{|a| m.unit(a.to_s) },
lambda{|b| m.unit(b.length) }).call(450)
> m.unit(3)
77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/fr/monad.rb', line 77 def composeM(f, g = nil, &block) rest = lambda do |g| lambda do |a| bind(f.call(a)) do |b| g.call(b) end end end (g.nil?) ? (block_given?) ? rest.call(block) : rest : rest.call(g) end |
#filterM(f, as = nil) ⇒ Object
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/fr/monad.rb', line 101 def filterM(f, as = nil) rec = lambda do |as| if as.empty? unit([]) else a, *as = as bind(f.call(a)) do |bool| bind(rec.call(as)) do |rest| unit(bool ? a.cons(rest) : rest) end end end end (as.nil?) ? rec : rec.call(as) end |
#foldM(f, seed = nil, bs = nil) ⇒ Object
-
Monad m => (a -> b -> m a) -> a -> [b] -> m a
>> m.foldM(lambda{|a,b| m.unit(a | b) }).call(0).call()
> m.unit(7)
Not implemented: >> [1,2,4].foldM(0){|a,b| m.unit(a | b) }
> m.unit(7)
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/fr/monad.rb', line 152 def foldM(f, seed = nil, bs = nil) rest = lambda do |seed| lambda do |bs| if bs.empty? unit(seed) else b, *bs = bs bind(f.call(seed, b)) do |seed_| rec.call(seed_).call(bs) end end end end (bs.nil?) ? (seed.nil?) ? rest : rest.call(seed) : rest.call(seed).call(bs) end |
#forM(as, f = nil, &block) ⇒ Object
59 60 61 62 63 64 65 66 67 68 |
# File 'lib/fr/monad.rb', line 59 def forM(as, f = nil, &block) rest = lambda do |f| sequence(as.map(&block)) end (f.nil?) ? (block_given?) ? rest.call(block) : rest : rest.call(f) end |
#join(mm) ⇒ Object
Remove one level of monadic structure
-
Monad m => m (m a) -> m a
>> m.join(m.unit(m.unit(100)))
> m.unit(100)
>> Array.join([,[2],])
> [1,2,3]
29 30 31 |
# File 'lib/fr/monad.rb', line 29 def join(mm) bind(mm){|x| x } end |
#liftM(f = nil, ma = nil, &block) ⇒ Object Also known as: map
-
Monad m => (a -> b) -> m a -> m b
>> m.liftM(lambda{|x| x.even? }).call(m.unit(30))
> m.unit(true)
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/fr/monad.rb', line 187 def liftM(f = nil, ma = nil, &block) rest = lambda do |f| lambda do |ma| bind(ma) do |a| unit(f.call(a)) end end end (ma.nil?) ? (block_given?) ? rest.call(block).call(f) :# m.liftM(ma){ .. } rest.call(f) :# m.liftM(lambda{ .. }).call(ma) rest.call(f).call(ma) # m.liftM(lambda{ .. }, ma) end |
#mapM(f, as = nil) ⇒ Object
38 39 40 41 42 43 44 45 46 |
# File 'lib/fr/monad.rb', line 38 def mapM(f, as = nil) if as.nil? lambda do |as| sequence(as.map(&f)) end else sequence(as.map(&f)) end end |
#sequence(ms) ⇒ Object
Perform each action, from left to right
-
Monad m => [m a] -> m [a]
@todo: Need trampoline for 2500+ ms
10 11 12 13 14 15 16 17 18 |
# File 'lib/fr/monad.rb', line 10 def sequence(ms) ms.inject(unit []) do |prev, curr| bind(prev) do |xs| bind(curr) do |x| unit(xs + [x]) end end end end |
#unlessM(condition) ⇒ Object
-
Monad m => Bool -> m () -> m ()
178 179 180 |
# File 'lib/fr/monad.rb', line 178 def unlessM(condition) # todo end |
#whenM(condition) ⇒ Object
-
Monad m => Bool -> m () -> m ()
173 174 175 |
# File 'lib/fr/monad.rb', line 173 def whenM(condition) # todo end |
#zipM(f, xs = nil, ys = nil) ⇒ Object
-
Monad m => (a -> b -> m c) -> [a] -> [b] -> m [c]
>> m.zipM(lambda{|a,b| m.unit(a + b) }).call().call()
> m.unit()
Not implemented: >> [1,2,3].zipM(){|a,b| m.unit(a + b) }
> m.unit()
130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/fr/monad.rb', line 130 def zipM(f, xs = nil, ys = nil) rest = lambda do |xs| lambda do |ys| sequence(xs.zip(ys).map{|(x,y)| f.call(x, y) }) end end (ys.nil?) ? (xs.nil?) ? rest : rest.call(xs) : rest.call(xs).call(ys) end |