kleisli 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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