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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3542c8f4abc331bb9a9d47170b22392146489666
4
- data.tar.gz: 4381c9631f3205faffc3a3764340d3ce2c623041
3
+ metadata.gz: d1dcb8005f78840e1bebfc588e75a579e1f5057d
4
+ data.tar.gz: f1c1307b95152674449ea4822fc6b70c4344cd59
5
5
  SHA512:
6
- metadata.gz: 52389420ffa39afd4fcb73731e95301d9258374e26f85afd1e467330cc61764d5b7c9989d0ef7309948cbc2134237ee5a8970325028f2fea67281b56ac8eb584
7
- data.tar.gz: bf55220e96e5649b079588c661d2e7ff430197c8964bfa75971d78b7937fd29a29ae3b6a6e98c1b235d82b5490bd9eb97e4ff0baa4f4f17dffd91e360be66364
6
+ metadata.gz: 5761487fddc055ad871ee6bcbbf4459eb06fe6eba201252dc5ddee9121057b804accb6286e99c360924cecd9e176daf20a3c2da4cf350a53d1afabb6aee40f80
7
+ data.tar.gz: 8e3c8e5b13ca0bc23abc9c7155fe0ac078d2e00e2a319a47ab380ae2ee25b30afe5118a0111cf8b7f4bbf7db93eed87bdfbed6b6cf9f8b454b1aee4a6accc2fb
data/.gitignore CHANGED
@@ -12,3 +12,4 @@
12
12
  *.o
13
13
  *.a
14
14
  mkmf.log
15
+ *.gem
data/.travis.yml ADDED
@@ -0,0 +1,10 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.1.2
5
+ - rbx-2
6
+ - ruby-head
7
+ - jruby-head
8
+
9
+ script:
10
+ - rake
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 Josep M. Bach
1
+ Copyright (c) 2014 Josep M. Bach, Ryan Levick
2
2
 
3
3
  MIT License
4
4
 
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, written by [Ryan Levick][rylev] and me.
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 real app, not a proof of concept.
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 `return` is a reserved keyword in Ruby) with convenience global methods (see which for each monad below).
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 looks like this: `>->`. We will probably burn in hell for this.
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
@@ -4,6 +4,7 @@ require "kleisli/try"
4
4
  require "kleisli/writer"
5
5
  require "kleisli/future"
6
6
  require "kleisli/either"
7
+ require "kleisli/composition"
7
8
 
8
9
  module Kleisli
9
10
  end
@@ -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
@@ -5,5 +5,9 @@ module Kleisli
5
5
  def >(block)
6
6
  raise NotImplementedError, "this monad doesn't implement >->"
7
7
  end
8
+
9
+ def >>(block)
10
+ self > block
11
+ end
8
12
  end
9
13
  end
@@ -1,3 +1,3 @@
1
1
  module Kleisli
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -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() >-> x { Maybe(x * 2) }
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) >-> x { Maybe(x * 2) }
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.1
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-31 00:00:00.000000000 Z
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
- - ".gitignore"
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.2.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