kleisli 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +10 -0
- data/LICENSE.txt +1 -1
- data/README.md +58 -5
- data/lib/kleisli.rb +1 -0
- data/lib/kleisli/composition.rb +44 -0
- data/lib/kleisli/monad.rb +4 -0
- data/lib/kleisli/version.rb +1 -1
- data/test/kleisli/maybe_test.rb +2 -2
- metadata +12 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d1dcb8005f78840e1bebfc588e75a579e1f5057d
|
4
|
+
data.tar.gz: f1c1307b95152674449ea4822fc6b70c4344cd59
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5761487fddc055ad871ee6bcbbf4459eb06fe6eba201252dc5ddee9121057b804accb6286e99c360924cecd9e176daf20a3c2da4cf350a53d1afabb6aee40f80
|
7
|
+
data.tar.gz: 8e3c8e5b13ca0bc23abc9c7155fe0ac078d2e00e2a319a47ab380ae2ee25b30afe5118a0111cf8b7f4bbf7db93eed87bdfbed6b6cf9f8b454b1aee4a6accc2fb
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,10 @@
|
|
1
|
-
# Kleisli
|
1
|
+
# Kleisli [![Build Status](https://secure.travis-ci.org/txus/adts.png)](http://travis-ci.org/txus/adts)
|
2
2
|
|
3
|
-
An idiomatic, clean implementation of a few common useful monads in Ruby,
|
3
|
+
An idiomatic, clean implementation of a few common useful monads in Ruby,
|
4
|
+
written by [Ryan Levick][rylev] and me.
|
4
5
|
|
5
|
-
It aims to be idiomatic Ruby to use in
|
6
|
+
It aims to be idiomatic Ruby to use in Enter-Prise production apps, not a proof
|
7
|
+
of concept.
|
6
8
|
|
7
9
|
In your Gemfile:
|
8
10
|
|
@@ -14,9 +16,54 @@ We would like to thank Curry and Howard for their correspondence.
|
|
14
16
|
|
15
17
|
## Notation
|
16
18
|
|
17
|
-
For all its monads, Kleisli implements `return` (we call it `lift` instead, as
|
19
|
+
For all its monads, Kleisli implements `return` (we call it `lift` instead, as
|
20
|
+
`return` is a reserved keyword in Ruby) with convenience global methods (see
|
21
|
+
which for each monad below).
|
18
22
|
|
19
|
-
Kleisli uses a clever Ruby syntax trick to implement the `bind` operator, which
|
23
|
+
Kleisli uses a clever Ruby syntax trick to implement the `bind` operator, which
|
24
|
+
looks like this: `>->` when used with a block. We will probably burn in hell
|
25
|
+
for this. You can also use `>` or `>>` if you're going to pass in a proc or
|
26
|
+
lambda object.
|
27
|
+
|
28
|
+
### Function composition
|
29
|
+
|
30
|
+
You can use Haskell-like function composition with F and the familiar `.`. This
|
31
|
+
is such a perversion of Ruby syntax that Matz would probably condemn this:
|
32
|
+
|
33
|
+
Think of `F` as the identity function. Although it's just a hack to make it
|
34
|
+
work in Ruby.
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
# Reminder that (f . g) x= f(g(x))
|
38
|
+
f = F . first . last
|
39
|
+
f.call [[1,2], [3,4]]
|
40
|
+
# => 3
|
41
|
+
|
42
|
+
f = F . capitalize . reverse
|
43
|
+
f.call "hello"
|
44
|
+
# => "Olleh"
|
45
|
+
```
|
46
|
+
|
47
|
+
Functions and methods are interchangeable:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
def foo(s)
|
51
|
+
s.reverse
|
52
|
+
end
|
53
|
+
|
54
|
+
f = F . capitalize . foo
|
55
|
+
f.call "hello"
|
56
|
+
# => "Olleh"
|
57
|
+
```
|
58
|
+
|
59
|
+
All functions and methods are partially applicable:
|
60
|
+
|
61
|
+
```ruby
|
62
|
+
|
63
|
+
f = F . split(":") . strip
|
64
|
+
puts f.call " localhost:9092 "
|
65
|
+
# => ["localhost", "9092"]
|
66
|
+
```
|
20
67
|
|
21
68
|
## Maybe monad
|
22
69
|
|
@@ -40,6 +87,9 @@ maybe_user = Maybe(user) >-> user {
|
|
40
87
|
# You can also use Some and None as type constructors yourself.
|
41
88
|
x = Some(10)
|
42
89
|
y = None()
|
90
|
+
|
91
|
+
# Now using fancy point-free style:
|
92
|
+
Maybe(user) >> F . Maybe . address >> F . Maybe . street
|
43
93
|
```
|
44
94
|
|
45
95
|
### `fmap`
|
@@ -233,6 +283,9 @@ writer = Writer([], 100).fmap { |value|
|
|
233
283
|
|
234
284
|
The Future monad models a pipeline of computations that will happen in the future, as soon as the value needed for each step is available. It is useful to model, for example, a sequential chain of HTTP calls.
|
235
285
|
|
286
|
+
There's a catch unfortunately -- values passed to the functions are wrapped in
|
287
|
+
lambdas, so you need to call `.call` on them. See the examples below.
|
288
|
+
|
236
289
|
### `>->` (bind)
|
237
290
|
|
238
291
|
```ruby
|
data/lib/kleisli.rb
CHANGED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'blankslate'
|
2
|
+
|
3
|
+
class Proc
|
4
|
+
def self.comp(f, g)
|
5
|
+
lambda { |*args| f[g[*args]] }
|
6
|
+
end
|
7
|
+
|
8
|
+
def *(g)
|
9
|
+
Proc.comp(self, g)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module Kleisli
|
14
|
+
class ComposedFn < BlankSlate
|
15
|
+
def initialize(fns=[])
|
16
|
+
@fns = fns
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_missing(m, *args, &block)
|
20
|
+
fn = -> a, x {
|
21
|
+
|
22
|
+
puts "A: #{a.inspect}"
|
23
|
+
puts "M: #{m.inspect}"
|
24
|
+
puts "X: #{x.inspect}"
|
25
|
+
if x.respond_to?(m)
|
26
|
+
x.send(m, *a)
|
27
|
+
else
|
28
|
+
send(m, *a)
|
29
|
+
end
|
30
|
+
}.curry[args]
|
31
|
+
ComposedFn.new(@fns + [fn])
|
32
|
+
end
|
33
|
+
|
34
|
+
def call(*args)
|
35
|
+
@fns.reduce(:*).call(*args)
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_ary
|
39
|
+
@fns.to_ary
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
F = Kleisli::ComposedFn.new
|
data/lib/kleisli/monad.rb
CHANGED
data/lib/kleisli/version.rb
CHANGED
data/test/kleisli/maybe_test.rb
CHANGED
@@ -10,11 +10,11 @@ class MaybeTest < MiniTest::Unit::TestCase
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def test_bind_none
|
13
|
-
assert_equal None(), None()
|
13
|
+
assert_equal None(), None() >> F . Maybe . *(2)
|
14
14
|
end
|
15
15
|
|
16
16
|
def test_bind_some
|
17
|
-
assert_equal Some(6), Some(3)
|
17
|
+
assert_equal Some(6), Some(3) >> F . Maybe . *(2)
|
18
18
|
end
|
19
19
|
|
20
20
|
def test_fmap_none
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kleisli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Josep M. Bach
|
@@ -9,34 +9,34 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-10
|
12
|
+
date: 2014-11-10 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- -
|
18
|
+
- - ~>
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: '1.7'
|
21
21
|
type: :development
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- -
|
25
|
+
- - ~>
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '1.7'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: rake
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
31
31
|
requirements:
|
32
|
-
- -
|
32
|
+
- - ~>
|
33
33
|
- !ruby/object:Gem::Version
|
34
34
|
version: '10.0'
|
35
35
|
type: :development
|
36
36
|
prerelease: false
|
37
37
|
version_requirements: !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
|
-
- -
|
39
|
+
- - ~>
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
version: '10.0'
|
42
42
|
description: Usable, idiomatic common monads in Ruby
|
@@ -47,13 +47,15 @@ executables: []
|
|
47
47
|
extensions: []
|
48
48
|
extra_rdoc_files: []
|
49
49
|
files:
|
50
|
-
-
|
50
|
+
- .gitignore
|
51
|
+
- .travis.yml
|
51
52
|
- Gemfile
|
52
53
|
- LICENSE.txt
|
53
54
|
- README.md
|
54
55
|
- Rakefile
|
55
56
|
- kleisli.gemspec
|
56
57
|
- lib/kleisli.rb
|
58
|
+
- lib/kleisli/composition.rb
|
57
59
|
- lib/kleisli/either.rb
|
58
60
|
- lib/kleisli/functor.rb
|
59
61
|
- lib/kleisli/future.rb
|
@@ -80,17 +82,17 @@ require_paths:
|
|
80
82
|
- lib
|
81
83
|
required_ruby_version: !ruby/object:Gem::Requirement
|
82
84
|
requirements:
|
83
|
-
- -
|
85
|
+
- - '>='
|
84
86
|
- !ruby/object:Gem::Version
|
85
87
|
version: '0'
|
86
88
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
89
|
requirements:
|
88
|
-
- -
|
90
|
+
- - '>='
|
89
91
|
- !ruby/object:Gem::Version
|
90
92
|
version: '0'
|
91
93
|
requirements: []
|
92
94
|
rubyforge_project:
|
93
|
-
rubygems_version: 2.
|
95
|
+
rubygems_version: 2.0.14
|
94
96
|
signing_key:
|
95
97
|
specification_version: 4
|
96
98
|
summary: Usable, idiomatic common monads in Ruby
|