rb-kgy-fp 1.0.0
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 +7 -0
- data/lib/rb-kgy-fp/curry_fun.rb +351 -0
- data/lib/rb-kgy-fp/fun.rb +378 -0
- data/lib/rb-kgy-fp/lib.rb +1 -0
- data/lib/rb-kgy-fp/special.rb +27 -0
- data/lib/rb-kgy-fp/std_ext/array.rb +25 -0
- data/lib/rb-kgy-fp/std_ext/string.rb +19 -0
- data/lib/rb-kgy-fp/trait/alternative.rb +14 -0
- data/lib/rb-kgy-fp/trait/applicative.rb +32 -0
- data/lib/rb-kgy-fp/trait/bi_functor.rb +19 -0
- data/lib/rb-kgy-fp/trait/functor.rb +15 -0
- data/lib/rb-kgy-fp/trait/monad.rb +20 -0
- data/lib/rb-kgy-fp/trait/monoid.rb +24 -0
- data/lib/rb-kgy-fp/trait/semi_group.rb +8 -0
- data/lib/rb-kgy-fp/typeclass/either.rb +114 -0
- data/lib/rb-kgy-fp/typeclass/maybe.rb +113 -0
- data/lib/rb-kgy-fp/typeclass/reader.rb +64 -0
- data/lib/rb-kgy-fp/typeclass/state.rb +63 -0
- data/lib/rb-kgy-fp/typeclass/writer.rb +53 -0
- metadata +61 -0
@@ -0,0 +1 @@
|
|
1
|
+
# frozen_string_literal: true
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
|
5
|
+
module Special
|
6
|
+
private
|
7
|
+
class UnimplementedError < RuntimeError
|
8
|
+
def to_s
|
9
|
+
"Unimplemented Error: Please check the code for implementation"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
public
|
14
|
+
class PlaceHolder
|
15
|
+
include Singleton
|
16
|
+
end
|
17
|
+
|
18
|
+
PH = PlaceHolder.instance
|
19
|
+
|
20
|
+
class Optional
|
21
|
+
include Singleton
|
22
|
+
end
|
23
|
+
|
24
|
+
OPT = Optional.instance
|
25
|
+
|
26
|
+
UNIMPLEMENTED = UnimplementedError.new
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Array
|
4
|
+
def head
|
5
|
+
first
|
6
|
+
end
|
7
|
+
|
8
|
+
def tail
|
9
|
+
length <= 1 ? [] : last(length - 1)
|
10
|
+
end
|
11
|
+
|
12
|
+
def init
|
13
|
+
length == 0 ? [] : first(length - 1)
|
14
|
+
end
|
15
|
+
|
16
|
+
def xprod arr2
|
17
|
+
ret = []
|
18
|
+
self.each do |item1|
|
19
|
+
arr2.each do |item2|
|
20
|
+
ret << [item1, item2]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
ret
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "lib/special"
|
4
|
+
require 'lib/fun'
|
5
|
+
require 'lib/curry_fun'
|
6
|
+
require 'lib/trait/functor'
|
7
|
+
|
8
|
+
module Applicative
|
9
|
+
include Functor
|
10
|
+
|
11
|
+
# implement require: apply | lift_a2
|
12
|
+
# of is required as class method
|
13
|
+
|
14
|
+
# <*>
|
15
|
+
def apply other
|
16
|
+
lift_a2(other, &Fun.method(:id))
|
17
|
+
end
|
18
|
+
|
19
|
+
def lift_a2 other, &fn
|
20
|
+
apply(other.map(&fn))
|
21
|
+
end
|
22
|
+
|
23
|
+
# *>
|
24
|
+
def replace other
|
25
|
+
update(Fun.method(:id)).apply(other)
|
26
|
+
end
|
27
|
+
|
28
|
+
# <*
|
29
|
+
def const other
|
30
|
+
lift_a2(other, &CurryFun.method(:const))
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'lib/special'
|
4
|
+
require 'lib/fun'
|
5
|
+
|
6
|
+
module BiFunctor
|
7
|
+
# implement require: bimap | (first, second)
|
8
|
+
def bimap map_fst, map_snd
|
9
|
+
second(&map_snd).first(&map_fst)
|
10
|
+
end
|
11
|
+
|
12
|
+
def first &fn
|
13
|
+
bimap fn, Fun.method(:id)
|
14
|
+
end
|
15
|
+
|
16
|
+
def second &fn
|
17
|
+
bimap Fun.method(:id), fn
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'lib/special'
|
4
|
+
require 'lib/curry_fun'
|
5
|
+
require 'lib/trait/applicative'
|
6
|
+
|
7
|
+
module Monad
|
8
|
+
include Applicative
|
9
|
+
|
10
|
+
# >>=
|
11
|
+
def bind & fn
|
12
|
+
raise Special::UNIMPLEMENTED
|
13
|
+
end
|
14
|
+
|
15
|
+
# >>
|
16
|
+
def consume other
|
17
|
+
bind { |_| other }
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'lib/special'
|
4
|
+
require 'lib/trait/semi_group'
|
5
|
+
|
6
|
+
module Monoid
|
7
|
+
include SemiGroup
|
8
|
+
|
9
|
+
# implement require: mempty | mconcat
|
10
|
+
|
11
|
+
def self.mempty
|
12
|
+
mconcat []
|
13
|
+
end
|
14
|
+
|
15
|
+
def mappend other
|
16
|
+
assoc(other)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.mconcat ls
|
20
|
+
ls.reverse.reduce(mempty) do |acc, item|
|
21
|
+
acc.mappend(item)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'lib/special'
|
4
|
+
require 'lib/fun'
|
5
|
+
require 'lib/curry_fun'
|
6
|
+
require 'lib/trait/semi_group'
|
7
|
+
require 'lib/trait/monad'
|
8
|
+
require 'lib/trait/bi_functor'
|
9
|
+
|
10
|
+
class Either
|
11
|
+
include SemiGroup, Monad, Comparable, BiFunctor
|
12
|
+
|
13
|
+
attr_reader :value
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
public
|
18
|
+
|
19
|
+
def initialize value
|
20
|
+
@value = value
|
21
|
+
end
|
22
|
+
|
23
|
+
def left?
|
24
|
+
raise Special::UNIMPLEMENTED
|
25
|
+
end
|
26
|
+
|
27
|
+
def right?
|
28
|
+
!left?
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.of value
|
32
|
+
Right.new value
|
33
|
+
end
|
34
|
+
|
35
|
+
def either map_left, map_right
|
36
|
+
raise Special::UNIMPLEMENTED
|
37
|
+
end
|
38
|
+
|
39
|
+
def <=> other
|
40
|
+
if right?
|
41
|
+
other.left? ? -1 : @value <=> other.value
|
42
|
+
else
|
43
|
+
other.right? ? 1 : @value <=> other.value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Left < Either
|
49
|
+
def assoc other
|
50
|
+
other
|
51
|
+
end
|
52
|
+
|
53
|
+
def fmap & fn
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
def apply(other)
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
def bind(&fn)
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
def left?
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
def to_s
|
70
|
+
"Left(#{@value})"
|
71
|
+
end
|
72
|
+
|
73
|
+
def either(map_left, _)
|
74
|
+
map_left.(@value)
|
75
|
+
end
|
76
|
+
|
77
|
+
def bimap(map_fst, map_snd)
|
78
|
+
Left.new map_fst.(@value)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class Right < Either
|
83
|
+
def assoc other
|
84
|
+
self
|
85
|
+
end
|
86
|
+
|
87
|
+
def fmap & fn
|
88
|
+
of fn.(@value)
|
89
|
+
end
|
90
|
+
|
91
|
+
def apply(other)
|
92
|
+
of @value.(other)
|
93
|
+
end
|
94
|
+
|
95
|
+
def bind(&fn)
|
96
|
+
fn.(@value)
|
97
|
+
end
|
98
|
+
|
99
|
+
def left?
|
100
|
+
false
|
101
|
+
end
|
102
|
+
|
103
|
+
def to_s
|
104
|
+
"Right(#{@value})"
|
105
|
+
end
|
106
|
+
|
107
|
+
def either(_, map_right)
|
108
|
+
map_right.(@value)
|
109
|
+
end
|
110
|
+
|
111
|
+
def bimap(map_fst, map_snd)
|
112
|
+
of map_snd.(@value)
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'lib/special'
|
4
|
+
require 'lib/fun'
|
5
|
+
require 'lib/curry_fun'
|
6
|
+
require 'lib/trait/monad'
|
7
|
+
require 'lib/trait/alternative'
|
8
|
+
|
9
|
+
class Maybe
|
10
|
+
include Monad, Alternative, Comparable
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
public
|
15
|
+
|
16
|
+
def just?
|
17
|
+
raise Special::UNIMPLEMENTED
|
18
|
+
end
|
19
|
+
|
20
|
+
def nothing?
|
21
|
+
!just?
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.of value
|
25
|
+
Just.new value
|
26
|
+
end
|
27
|
+
|
28
|
+
def <=> other
|
29
|
+
if just?
|
30
|
+
other.nothing? ? -1 : @value <=> other.value
|
31
|
+
else
|
32
|
+
other.nothing? ? 0 : 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.empty
|
37
|
+
Nothing.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def consume(other)
|
41
|
+
replace other
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class Just < Maybe
|
46
|
+
attr_reader :value
|
47
|
+
def initialize value
|
48
|
+
@value = value
|
49
|
+
end
|
50
|
+
|
51
|
+
def just?
|
52
|
+
true
|
53
|
+
end
|
54
|
+
|
55
|
+
def fmap(&fn)
|
56
|
+
of fn.(@value)
|
57
|
+
end
|
58
|
+
|
59
|
+
def apply(other)
|
60
|
+
other.fmap(&@value)
|
61
|
+
end
|
62
|
+
|
63
|
+
def lift_a2(other, &fn)
|
64
|
+
if other.just?
|
65
|
+
of fn.(@value, other.value)
|
66
|
+
else
|
67
|
+
Nothing.new
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def replace(other)
|
72
|
+
other
|
73
|
+
end
|
74
|
+
|
75
|
+
def or(other)
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
def bind(&fn)
|
80
|
+
fn.(@value)
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
class Nothing < Maybe
|
86
|
+
def just?
|
87
|
+
false
|
88
|
+
end
|
89
|
+
|
90
|
+
def fmap(&fn)
|
91
|
+
self
|
92
|
+
end
|
93
|
+
|
94
|
+
def apply(other)
|
95
|
+
self
|
96
|
+
end
|
97
|
+
|
98
|
+
def lift_a2(other, &fn)
|
99
|
+
self
|
100
|
+
end
|
101
|
+
|
102
|
+
def replace(other)
|
103
|
+
self
|
104
|
+
end
|
105
|
+
|
106
|
+
def or other
|
107
|
+
other
|
108
|
+
end
|
109
|
+
|
110
|
+
def bind(&fn)
|
111
|
+
self
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'lib/trait/monad'
|
4
|
+
require 'lib/fun'
|
5
|
+
require 'lib/curry_fun'
|
6
|
+
|
7
|
+
class Reader
|
8
|
+
include Monad
|
9
|
+
|
10
|
+
private_class_method :new
|
11
|
+
|
12
|
+
def self.of &reader
|
13
|
+
new &reader
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.ask
|
17
|
+
of &Fun.method(:id)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.asks &fn
|
21
|
+
of do |env|
|
22
|
+
fn.(ask.run_reader(env))
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def initialize &reader
|
29
|
+
@reader = reader
|
30
|
+
end
|
31
|
+
|
32
|
+
public
|
33
|
+
|
34
|
+
def fmap(&fn)
|
35
|
+
of do |env|
|
36
|
+
fn.(run_reader(env))
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def apply(other)
|
41
|
+
of do |env|
|
42
|
+
run_reader(env).run_reader(env)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def bind(&fn)
|
47
|
+
of do |env|
|
48
|
+
fst = run_reader(env)
|
49
|
+
fn.(fst).run_reader(env)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def run_reader env
|
54
|
+
@reader.(env)
|
55
|
+
end
|
56
|
+
|
57
|
+
def map_reader &fn
|
58
|
+
of CurryFun.pipe(@reader, fn)
|
59
|
+
end
|
60
|
+
|
61
|
+
def with_reader &fn
|
62
|
+
of CurryFun.pipe(fn, @reader)
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'lib/trait/monad'
|
4
|
+
|
5
|
+
class State
|
6
|
+
include Monad
|
7
|
+
|
8
|
+
private_class_method :new
|
9
|
+
|
10
|
+
def self.of & action
|
11
|
+
new &action
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.get
|
15
|
+
of { |s| [s, s] }
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.put state
|
19
|
+
of { |_| [nil, state] }
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def initialize & action
|
25
|
+
@action = action
|
26
|
+
end
|
27
|
+
|
28
|
+
public
|
29
|
+
|
30
|
+
def fmap(&fn)
|
31
|
+
of do |state|
|
32
|
+
run_state(state) => [value, this_state]
|
33
|
+
[fn.(value), this_state]
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def apply(other)
|
38
|
+
of do |state|
|
39
|
+
run_state(state) => [fn, this_state]
|
40
|
+
other.run_state(this_state) => [value, other_state]
|
41
|
+
[fn.(value), other_state]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def bind & fn
|
46
|
+
of do |s|
|
47
|
+
run_state(s) => [value, this_state]
|
48
|
+
fn.(value).run_state(this_state)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def run_state state
|
53
|
+
@action.(state)
|
54
|
+
end
|
55
|
+
|
56
|
+
def eval_state state
|
57
|
+
run_state(state)[0]
|
58
|
+
end
|
59
|
+
|
60
|
+
def exec_state state
|
61
|
+
run_state(state)[1]
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'lib/trait/monad'
|
4
|
+
|
5
|
+
class Writer
|
6
|
+
include Monad
|
7
|
+
|
8
|
+
private_class_method :new
|
9
|
+
|
10
|
+
def self.of value, stack
|
11
|
+
new value, stack
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.tell stack = []
|
15
|
+
of nil, stack
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def initialize value = nil, stack = []
|
21
|
+
@value = value
|
22
|
+
@stack = stack
|
23
|
+
@stack.freeze
|
24
|
+
@stack.each { |item| item.freeze }
|
25
|
+
end
|
26
|
+
|
27
|
+
public
|
28
|
+
|
29
|
+
def fmap(&fn)
|
30
|
+
of fn.(@value), @stack
|
31
|
+
end
|
32
|
+
|
33
|
+
def apply(other)
|
34
|
+
of @value.(other.map_writer), [*@stack, *other.exec_writer]
|
35
|
+
end
|
36
|
+
|
37
|
+
def bind(&fn)
|
38
|
+
fn.(@value).run_writer => [new_value, new_stack]
|
39
|
+
of new_value, [*@stack, *new_stack]
|
40
|
+
end
|
41
|
+
|
42
|
+
def run_writer
|
43
|
+
[@value, @stack]
|
44
|
+
end
|
45
|
+
|
46
|
+
def exec_writer
|
47
|
+
@stack
|
48
|
+
end
|
49
|
+
|
50
|
+
def map_writer
|
51
|
+
@value
|
52
|
+
end
|
53
|
+
end
|
metadata
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rb-kgy-fp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Phil Lui
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-09-02 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Ruby FP lib for self usage. This lib included simple FP functions like
|
14
|
+
Rmada of JS, and different typeclass support as Haskell
|
15
|
+
email: phillui37@gmail.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/rb-kgy-fp/curry_fun.rb
|
21
|
+
- lib/rb-kgy-fp/fun.rb
|
22
|
+
- lib/rb-kgy-fp/lib.rb
|
23
|
+
- lib/rb-kgy-fp/special.rb
|
24
|
+
- lib/rb-kgy-fp/std_ext/array.rb
|
25
|
+
- lib/rb-kgy-fp/std_ext/string.rb
|
26
|
+
- lib/rb-kgy-fp/trait/alternative.rb
|
27
|
+
- lib/rb-kgy-fp/trait/applicative.rb
|
28
|
+
- lib/rb-kgy-fp/trait/bi_functor.rb
|
29
|
+
- lib/rb-kgy-fp/trait/functor.rb
|
30
|
+
- lib/rb-kgy-fp/trait/monad.rb
|
31
|
+
- lib/rb-kgy-fp/trait/monoid.rb
|
32
|
+
- lib/rb-kgy-fp/trait/semi_group.rb
|
33
|
+
- lib/rb-kgy-fp/typeclass/either.rb
|
34
|
+
- lib/rb-kgy-fp/typeclass/maybe.rb
|
35
|
+
- lib/rb-kgy-fp/typeclass/reader.rb
|
36
|
+
- lib/rb-kgy-fp/typeclass/state.rb
|
37
|
+
- lib/rb-kgy-fp/typeclass/writer.rb
|
38
|
+
homepage: https://github.com/phillui-37/rb-kgy-fp
|
39
|
+
licenses:
|
40
|
+
- MIT
|
41
|
+
metadata: {}
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
require_paths:
|
45
|
+
- lib
|
46
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
requirements: []
|
57
|
+
rubygems_version: 3.4.10
|
58
|
+
signing_key:
|
59
|
+
specification_version: 4
|
60
|
+
summary: Ruby FP lib for self usage
|
61
|
+
test_files: []
|