prelude 0.0.3 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +25 -1
- data/README +11 -12
- data/Rakefile +6 -10
- data/lib/prelude.rb +36 -91
- data/lib/prelude/{tuple.rb → array_list.rb} +30 -27
- data/lib/prelude/functions.rb +414 -0
- data/lib/prelude/functors.rb +72 -0
- data/lib/prelude/lambda.rb +89 -0
- data/lib/prelude/minimal_array_list.rb +61 -0
- data/lib/prelude/monad.rb +11 -15
- data/lib/prelude/proper_list.rb +47 -0
- data/lib/prelude/proper_ruby_list.rb +48 -0
- data/lib/prelude/util.rb +33 -0
- data/test/tc_functions.rb +801 -0
- data/test/tc_monad.rb +21 -41
- data/test/ts_prelude.rb +2 -8
- metadata +13 -36
- data/doc/classes/Kernel.html +0 -198
- data/doc/classes/Prelude.html +0 -241
- data/doc/classes/Prelude/EmptyListError.html +0 -113
- data/doc/classes/Prelude/List.html +0 -2692
- data/doc/classes/Prelude/MissingFunctionError.html +0 -113
- data/doc/classes/Prelude/Monad.html +0 -283
- data/doc/classes/Prelude/Tuple.html +0 -217
- data/doc/classes/Proc.html +0 -198
- data/doc/classes/Symbol.html +0 -219
- data/doc/created.rid +0 -1
- data/doc/files/CHANGELOG.html +0 -122
- data/doc/files/README.html +0 -328
- data/doc/files/TODO.html +0 -95
- data/doc/files/lib/prelude/list_rb.html +0 -83
- data/doc/files/lib/prelude/monad_rb.html +0 -83
- data/doc/files/lib/prelude/tuple_rb.html +0 -83
- data/doc/files/lib/prelude_rb.html +0 -98
- data/doc/fr_class_index.html +0 -35
- data/doc/fr_file_index.html +0 -33
- data/doc/fr_method_index.html +0 -140
- data/doc/index.html +0 -27
- data/doc/rdoc-style.css +0 -208
- data/lib/prelude/list.rb +0 -588
- data/test/tc_higher.rb +0 -89
- data/test/tc_list.rb +0 -777
- data/test/tc_tuple.rb +0 -82
data/CHANGELOG
CHANGED
@@ -1,6 +1,30 @@
|
|
1
1
|
= CHANGELOG
|
2
2
|
|
3
|
-
$Id: CHANGELOG
|
3
|
+
$Id: CHANGELOG 34 2007-10-23 21:38:09Z prelude $
|
4
|
+
|
5
|
+
== 10/23/07 - Release 0.0.5
|
6
|
+
* Converted the implementation from function-based to constant-based, i.e., instead of
|
7
|
+
|
8
|
+
def and_(list)
|
9
|
+
foldr(lambda {|x,y| x && y}, true, list)
|
10
|
+
end
|
11
|
+
|
12
|
+
we define
|
13
|
+
|
14
|
+
AND = Lambda.new { |list|
|
15
|
+
FOLDR[BOOL_AND, true, list]
|
16
|
+
}
|
17
|
+
|
18
|
+
wich gives us an ability to do this
|
19
|
+
|
20
|
+
ALL = AND * MAP
|
21
|
+
|
22
|
+
instead of
|
23
|
+
|
24
|
+
def all(f, list)
|
25
|
+
and_(~map(f, list))
|
26
|
+
end
|
27
|
+
|
4
28
|
|
5
29
|
== 09/17/06 - Release 0.0.3
|
6
30
|
* Converted List from being functional-like to fully functional, i.e., all its methods return functions.
|
data/README
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
= Prelude - a Haskell-like functional library
|
2
2
|
|
3
|
-
$Id: README
|
3
|
+
$Id: README 34 2007-10-23 21:38:09Z prelude $
|
4
4
|
|
5
|
-
*WARNING* <tt>The project is still in a very preliminary state.
|
6
|
-
List was partially implemented. Feel free to contribute.</tt>
|
5
|
+
*WARNING* <tt>The project is still in a very preliminary state. Feel free to contribute.</tt>
|
7
6
|
|
8
7
|
Project home is at http://rubyforge.org/projects/prelude/
|
9
8
|
|
@@ -29,10 +28,10 @@ a wish list, so treat it accordingly.
|
|
29
28
|
=== Rather curious collection of operations on lists
|
30
29
|
|
31
30
|
Haskell's lists are different from Ruby's arrays in many ways. First
|
32
|
-
of all, there are more operations defined on lists and the
|
33
|
-
convention is different. Since Haskell's (or Lisp's) lists play
|
34
|
-
fundamental role in everything functional, their implementation
|
35
|
-
necessary. Here are the goals for list's implementation:
|
31
|
+
of all, there are more operations defined on lists and, second, the
|
32
|
+
naming convention is different. Since Haskell's (or Lisp's) lists play
|
33
|
+
a fundamental role in everything functional, their implementation
|
34
|
+
seems necessary. Here are the goals for list's implementation:
|
36
35
|
|
37
36
|
* Most, if not all, functions, i.e., +head+, +tail+, +last+, +first+, +concat+, etc.
|
38
37
|
|
@@ -66,8 +65,8 @@ While implementing majority of the Lambda world is relatively trivial
|
|
66
65
|
in Ruby, some of the recursive beauty might be lost. Consider +foldl+,
|
67
66
|
for example. The classic recursive definition like this
|
68
67
|
|
69
|
-
def foldl(s,
|
70
|
-
|
68
|
+
def foldl(f, s, list)
|
69
|
+
list.empty? ? s : f(foldl(f, s, list.tail), list.head)
|
71
70
|
end
|
72
71
|
|
73
72
|
croaks on about 800+ elements integer lists, but more rubyish and
|
@@ -91,7 +90,7 @@ them. These need to be added to complete the picture:
|
|
91
90
|
|
92
91
|
add5 = proc {|x| x+5}
|
93
92
|
add6 = proc {|x| x+6}
|
94
|
-
add11 = add5
|
93
|
+
add11 = add5 * add6
|
95
94
|
|
96
95
|
I.e., the <tt>add5</tt> is an absolutely generic algorithm expressed
|
97
96
|
in terms of other functions as long as <tt>add5</tt> takes as an
|
@@ -112,7 +111,7 @@ them. These need to be added to complete the picture:
|
|
112
111
|
This is where all the previous trouble should start paying off
|
113
112
|
allowing an application to be structured like this:
|
114
113
|
|
115
|
-
result
|
114
|
+
result >> connect >> do_something >> delete_something >> so_on
|
116
115
|
|
117
116
|
Writing tutorials for monadic computations became a little industry in
|
118
117
|
itself, see http://nomaware.com/monads/html/index.html to get
|
@@ -123,7 +122,7 @@ http://haskell.org/haskellwiki/Books_and_tutorials#Using_monads
|
|
123
122
|
|
124
123
|
These features will be nice to have in a second release of the library:
|
125
124
|
|
126
|
-
* General purpose monadic parser library similar to Parsec, see http://www.cs.uu.nl/~daan/parsec.html
|
125
|
+
* General purpose monadic parser library similar to Parsec, see http://www.cs.uu.nl/~daan/parsec.html or its Ruby port, see http://rubyforge.org/projects/rparsec/
|
127
126
|
|
128
127
|
* Tools for automatic program verification and algebraic proofs
|
129
128
|
|
data/Rakefile
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# $Id: Rakefile
|
2
|
+
# $Id: Rakefile 31 2006-12-28 02:28:28Z prelude $
|
3
3
|
#
|
4
4
|
# This file is part of the Prelude library that provides tools to
|
5
5
|
# enable Haskell style functional programming in Ruby.
|
@@ -31,6 +31,7 @@
|
|
31
31
|
|
32
32
|
require 'rubygems'
|
33
33
|
require 'rake'
|
34
|
+
require 'rake/clean'
|
34
35
|
require 'rake/testtask'
|
35
36
|
require 'rake/rdoctask'
|
36
37
|
require 'rake/packagetask'
|
@@ -46,11 +47,6 @@ PKG_VERSION = Prelude::VERSION
|
|
46
47
|
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
47
48
|
PKG_DESTINATION = "../#{PKG_NAME}"
|
48
49
|
|
49
|
-
RELEASE_NAME = "REL #{PKG_VERSION}"
|
50
|
-
|
51
|
-
RUBY_FORGE_PROJECT = "prelude"
|
52
|
-
RUBY_FORGE_USER = "prelude"
|
53
|
-
|
54
50
|
desc "Default Task"
|
55
51
|
task :default => [ :test ]
|
56
52
|
|
@@ -95,8 +91,8 @@ spec = Gem::Specification.new do |s|
|
|
95
91
|
s.description = 'Enables Ruby programmers to use higher-order functions, monads, and other Haskell features.'
|
96
92
|
s.author = 'Ivan K. and APP Design, Inc.'
|
97
93
|
s.email = 'prelude@rubyforge.org'
|
98
|
-
s.rubyforge_project =
|
99
|
-
s.homepage =
|
94
|
+
s.rubyforge_project = PKG_NAME
|
95
|
+
s.homepage = "http://#{PKG_NAME}.rubyforge.org"
|
100
96
|
|
101
97
|
s.has_rdoc = true
|
102
98
|
s.requirements << 'none'
|
@@ -118,8 +114,8 @@ spec = Gem::Specification.new do |s|
|
|
118
114
|
|x| x =~ /.*~/
|
119
115
|
end
|
120
116
|
end
|
121
|
-
puts "Files included into the GEM:"
|
122
|
-
pp s.files
|
117
|
+
puts "Files included into the GEM:" if $VERBOSE
|
118
|
+
pp s.files if $VERBOSE
|
123
119
|
|
124
120
|
s.test_files = Dir.glob( "test/**/ts_*rb" )
|
125
121
|
end
|
data/lib/prelude.rb
CHANGED
@@ -21,117 +21,62 @@
|
|
21
21
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
22
22
|
#++
|
23
23
|
#
|
24
|
-
# $Id: prelude.rb
|
24
|
+
# $Id: prelude.rb 34 2007-10-23 21:38:09Z prelude $
|
25
25
|
|
26
26
|
$:.unshift(File.dirname(__FILE__))
|
27
27
|
|
28
|
+
require 'prelude/util'
|
29
|
+
require 'prelude/array_list'
|
30
|
+
|
31
|
+
# WARNING: Somehow rdoc breaks on multiline constants and does not
|
32
|
+
# generate a full list of constants below. Please see the sources for
|
33
|
+
# all defined functions and functors, there are plenty and they are all
|
34
|
+
# defined as constants.
|
35
|
+
#
|
36
|
+
# The implementation of frequently used functors is based on the code
|
37
|
+
# from Ben Yu's rparsec library, see http://rubyforge.org/frs/?group_id=2326
|
28
38
|
module Prelude
|
29
39
|
|
30
|
-
VERSION='0.0.
|
40
|
+
VERSION = '0.0.5'
|
31
41
|
|
32
|
-
|
33
|
-
Id = lambda { |x| x }
|
42
|
+
LIST_IMPLEMENTATION = Prelude::ArrayList
|
34
43
|
|
35
44
|
# Thrown if an illegal operation is performed on an empty list.
|
36
45
|
class EmptyListError < RuntimeError; end
|
37
46
|
|
38
|
-
#
|
39
|
-
|
40
|
-
raise EmptyListError, 'Illegal operation on an empty list.'
|
41
|
-
end
|
47
|
+
# Thrown if a needed method is not available
|
48
|
+
class MissingMethodError < RuntimeError; end
|
42
49
|
|
43
50
|
# Thrown if no function was supplied
|
44
51
|
class MissingFunctionError < RuntimeError; end
|
45
52
|
|
46
|
-
#
|
47
|
-
|
48
|
-
raise MissingFunctionError, 'No function or block supplied.'
|
49
|
-
end
|
50
|
-
|
51
|
-
# A utility to determine if a function was passed
|
52
|
-
def get_proc(f=nil, &block)
|
53
|
-
# Has to be either function 'f' or block
|
54
|
-
f = block_given? ? block : missing_function_error if f.nil?
|
55
|
-
f.to_proc
|
56
|
-
end
|
57
|
-
|
58
|
-
end # Prelude
|
59
|
-
|
60
|
-
class Symbol
|
61
|
-
|
62
|
-
# Converts a symbol to a proc object
|
63
|
-
def to_proc
|
64
|
-
proc { |obj, *args| obj.send(self, *args) }
|
65
|
-
end
|
66
|
-
|
67
|
-
# Syntaxic sugar for something like this: -:+, i.e., defines proc object that executes 'plus'.
|
68
|
-
alias -@ to_proc
|
69
|
-
|
70
|
-
# FIXIT
|
71
|
-
def curry(one, *args)
|
72
|
-
proc { |*args| self.to_proc.call(one, *args) }
|
73
|
-
end
|
74
|
-
|
75
|
-
# This is will serve as an infix composition operator for symbols. If between two symbols,
|
76
|
-
# returns composition proc, executes left symbol otherwise.
|
77
|
-
def **(*args)
|
78
|
-
if (1==args.length) && args[0].is_a?(Symbol)
|
79
|
-
proc {|*a| self.to_proc.call(args[0].call(*a)) }
|
80
|
-
else
|
81
|
-
self.to_proc.call(*args.flatten)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end # Symbol
|
53
|
+
# Thrown if something wrong with the functions' arguments
|
54
|
+
class ArgumentError < RuntimeError; end
|
85
55
|
|
86
|
-
|
56
|
+
# Thrown if bad list is encountered
|
57
|
+
class ImproperListError < RuntimeError; end
|
87
58
|
|
88
|
-
#
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
lambda { |*args| self.call(one, *args)}
|
59
|
+
# A helper method to create an empty list of a given list type. Has to be a proper list.
|
60
|
+
def Prelude.new_list(list=nil)
|
61
|
+
res = LIST_IMPLEMENTATION.new(list)
|
62
|
+
#p "new_list #{res.inspect}"
|
63
|
+
raise ImproperListError unless res.kind_of?(Prelude::ProperList)
|
64
|
+
res
|
95
65
|
end
|
96
66
|
|
97
|
-
#
|
98
|
-
|
99
|
-
|
100
|
-
if (
|
101
|
-
|
67
|
+
# A helper method to generate a new lambda that uses native implementation if available
|
68
|
+
def Prelude.use_native(meth)
|
69
|
+
list = Prelude.new_list
|
70
|
+
if list.kind_of?(Prelude::ProperList) and list.respond_to?(meth)
|
71
|
+
Lambda.new { |l, *args| l.method(meth)[*args] }
|
102
72
|
else
|
103
|
-
|
73
|
+
nil
|
104
74
|
end
|
105
75
|
end
|
106
76
|
|
107
|
-
end #
|
108
|
-
|
109
|
-
module Kernel
|
110
|
-
|
111
|
-
# Method object for currently executing method
|
112
|
-
def this_method
|
113
|
-
name = (Kernel.caller[0] =~ /`([^']*)'/ and $1)
|
114
|
-
eval "self.method(\"#{name}\".to_sym)", binding
|
115
|
-
end
|
116
|
-
|
117
|
-
# Method object for the caller of the currently executing method
|
118
|
-
def caller_method
|
119
|
-
name = (Kernel.caller[1] =~ /`([^']*)'/ and $1)
|
120
|
-
eval "self.method(\"#{name}\".to_sym)", binding
|
121
|
-
end
|
122
|
-
|
123
|
-
# Shuts up Ruby's warning.
|
124
|
-
def silence_warnings
|
125
|
-
old_verbose, $VERBOSE = $VERBOSE, nil
|
126
|
-
yield
|
127
|
-
ensure
|
128
|
-
$VERBOSE = old_verbose
|
129
|
-
end
|
130
|
-
|
131
|
-
end # Kernel
|
77
|
+
end # Prelude
|
132
78
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
end
|
79
|
+
require 'prelude/lambda'
|
80
|
+
require 'prelude/functors'
|
81
|
+
require 'prelude/functions'
|
82
|
+
require 'prelude/monad'
|
@@ -21,40 +21,43 @@
|
|
21
21
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
22
22
|
#++
|
23
23
|
|
24
|
+
require 'prelude/minimal_array_list'
|
25
|
+
|
24
26
|
module Prelude
|
25
27
|
|
26
|
-
# $Id:
|
27
|
-
#
|
28
|
-
#
|
29
|
-
class
|
30
|
-
|
31
|
-
def initialize(
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
self[1] = nil
|
41
|
-
when args.length == 2 :
|
42
|
-
self[0] = args[0]
|
43
|
-
self[1] = args[1]
|
44
|
-
when args.length > 2 :
|
45
|
-
self[0] = args[0]
|
46
|
-
self[1] = args[1..-1]
|
47
|
-
end # case
|
28
|
+
# $Id: array_list.rb 34 2007-10-23 21:38:09Z prelude $
|
29
|
+
#
|
30
|
+
# Implemenation of the minimal list functionality based on Ruby's arrays
|
31
|
+
class ArrayList < Prelude::MinimalArrayList
|
32
|
+
|
33
|
+
def initialize(a=nil)
|
34
|
+
#p "new #{a.inspect}"
|
35
|
+
@arr = []
|
36
|
+
a.each { |e| @arr << (e.kind_of?(Array) ? ArrayList.new(e) : e) } if a
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def length
|
41
|
+
@arr.length
|
48
42
|
end
|
49
43
|
|
50
|
-
def
|
51
|
-
|
44
|
+
def append(list)
|
45
|
+
ArrayList.new(@arr+[*list])
|
52
46
|
end
|
53
47
|
|
54
|
-
def
|
55
|
-
|
48
|
+
def reverse
|
49
|
+
@arr.reverse
|
56
50
|
end
|
57
51
|
|
58
|
-
|
52
|
+
def transpose
|
53
|
+
@arr.transpose
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_a
|
57
|
+
res = []
|
58
|
+
@arr.each { |e| res << (e.kind_of?(ArrayList) ? e.to_a : e) }
|
59
|
+
res
|
60
|
+
end
|
59
61
|
|
62
|
+
end # ArrayList
|
60
63
|
end # Prelude
|
@@ -0,0 +1,414 @@
|
|
1
|
+
#--
|
2
|
+
# This file is part of the Prelude library that provides tools to
|
3
|
+
# enable Haskell style functional programming in Ruby.
|
4
|
+
#
|
5
|
+
# http://prelude.rubyforge.org
|
6
|
+
#
|
7
|
+
# Copyright (C) 2006 APP Design, Inc.
|
8
|
+
#
|
9
|
+
# This library is free software; you can redistribute it and/or
|
10
|
+
# modify it under the terms of the GNU Lesser General Public
|
11
|
+
# License as published by the Free Software Foundation; either
|
12
|
+
# version 2.1 of the License, or (at your option) any later version.
|
13
|
+
#
|
14
|
+
# This library is distributed in the hope that it will be useful,
|
15
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
17
|
+
# Lesser General Public License for more details.
|
18
|
+
#
|
19
|
+
# You should have received a copy of the GNU Lesser General Public
|
20
|
+
# License along with this library; if not, write to the Free Software
|
21
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
22
|
+
#++
|
23
|
+
# $Id: functions.rb 34 2007-10-23 21:38:09Z prelude $
|
24
|
+
|
25
|
+
module Prelude
|
26
|
+
|
27
|
+
# To handle error conditions
|
28
|
+
NOT_IMPLEMENTED_YET = Lambda.new { [] }
|
29
|
+
|
30
|
+
# (++)/append :: [a] -> [a] -> [a]
|
31
|
+
APPEND = Prelude.use_native(:append) || Lambda.new { |list1, list2|
|
32
|
+
#p "pp #{list1.inspect} #{list2.inspect}"
|
33
|
+
|
34
|
+
# Wrap non-list arguments.
|
35
|
+
list1 = new_list.cons(list1) unless list1.kind_of?(ProperList)
|
36
|
+
list2 = new_list.cons(list2) unless list2.kind_of?(ProperList)
|
37
|
+
|
38
|
+
case
|
39
|
+
when list1.null : list2
|
40
|
+
else APPEND[list1.tail, list2].cons(list1.head)
|
41
|
+
end
|
42
|
+
}
|
43
|
+
|
44
|
+
# last :: [a] -> a
|
45
|
+
LAST = Prelude.use_native(:last) || Lambda.new { |list|
|
46
|
+
case
|
47
|
+
when list.null : raise EmptyListError
|
48
|
+
when LENGTH[list] == 1 : list.head
|
49
|
+
else LAST[list.tail]
|
50
|
+
end
|
51
|
+
}
|
52
|
+
|
53
|
+
# init :: [a] -> [a]
|
54
|
+
INIT = Prelude.use_native(:init) || Lambda.new { |list|
|
55
|
+
case
|
56
|
+
when list.null : raise EmptyListError
|
57
|
+
when LENGTH[list] == 1 : new_list
|
58
|
+
else INIT[list.tail].cons(list.head)
|
59
|
+
end
|
60
|
+
}
|
61
|
+
|
62
|
+
# length :: [a] -> Int
|
63
|
+
LENGTH = Prelude.use_native(:length) || Lambda.new {|list|
|
64
|
+
case
|
65
|
+
when list.null : 0
|
66
|
+
else 1+LENGTH[list.tail]
|
67
|
+
end
|
68
|
+
}
|
69
|
+
|
70
|
+
# flip :: (a -> b -> c) -> b -> a -> c
|
71
|
+
FLIP = Lambda.new { |f, b, a|
|
72
|
+
#p "flip #{f.inspect} #{b.inspect} #{a.inspect}"
|
73
|
+
f[a, b]
|
74
|
+
}
|
75
|
+
|
76
|
+
# map :: (a -> b) -> [a] -> [b]
|
77
|
+
MAP = Lambda.new {|f, list|
|
78
|
+
#p "map #{f.inspect} #{list.inspect}"
|
79
|
+
case
|
80
|
+
when list.null : new_list
|
81
|
+
else MAP[f, list.tail].cons(f[list.head])
|
82
|
+
end
|
83
|
+
}
|
84
|
+
|
85
|
+
# reverse1 :: [a] -> [a]
|
86
|
+
REVERSE1 = Lambda.new { |list|
|
87
|
+
#p "reverse1 #{list.inspect}"
|
88
|
+
r = Lambda.new { |l, a|
|
89
|
+
#p "r #{l.inspect} #{a.inspect}"
|
90
|
+
case
|
91
|
+
when l.null : a
|
92
|
+
else r[l.tail, a.cons(l.head)]
|
93
|
+
end
|
94
|
+
}
|
95
|
+
r[list, new_list]
|
96
|
+
}
|
97
|
+
|
98
|
+
# reverse2 :: [a] -> [a]
|
99
|
+
REVERSE2 = Lambda.new { |list|
|
100
|
+
FOLDL[APPEND, new_list, list]
|
101
|
+
}
|
102
|
+
|
103
|
+
# reverse3 :: [a] -> [a]
|
104
|
+
REVERSE3 = Lambda.new { |list|
|
105
|
+
case
|
106
|
+
when list.null : new_list
|
107
|
+
else APPEND[REVERSE3[list.tail], new_list.cons(list.head)]
|
108
|
+
end
|
109
|
+
}
|
110
|
+
|
111
|
+
# reverse :: [a] -> [a]
|
112
|
+
REVERSE = Prelude.use_native(:reverse) || REVERSE1
|
113
|
+
|
114
|
+
# intersperse :: a -> [a] -> [a]
|
115
|
+
INTERSPERSE = Lambda.new { |a, list|
|
116
|
+
case
|
117
|
+
when list.null : new_list
|
118
|
+
when LENGTH[list] == 1 : list
|
119
|
+
else INTERSPERSE[a, list.tail].cons(a).cons(list.head)
|
120
|
+
end
|
121
|
+
}
|
122
|
+
|
123
|
+
# transpose :: [[a]] -> [[a]]
|
124
|
+
TRANSPOSE = Prelude.use_native(:transpose) || Lambda.new { |list|
|
125
|
+
# FIXIT
|
126
|
+
list.transpose
|
127
|
+
}
|
128
|
+
|
129
|
+
# # * Reducing lists (folds)
|
130
|
+
|
131
|
+
# foldl :: (a -> b -> a) -> a -> [b] -> a
|
132
|
+
FOLDL = Lambda.new { |f, s, list|
|
133
|
+
#p "foldl #{f.inspect} #{s.inspect} #{list.inspect}"
|
134
|
+
case
|
135
|
+
when list.null : s
|
136
|
+
else f[FOLDL[f, s, list.tail], list.head]
|
137
|
+
end
|
138
|
+
}
|
139
|
+
|
140
|
+
# foldl' :: (a -> b -> a) -> a -> [b] -> a
|
141
|
+
FOLDL_ = Lambda.new { |f, s, list|
|
142
|
+
warn "Method 'foldl_' is not implemented yet." if $VERBOSE
|
143
|
+
NOT_IMPLEMENTED_YET
|
144
|
+
}
|
145
|
+
|
146
|
+
# foldl1 :: (a -> a -> a) -> [a] -> a
|
147
|
+
FOLDL1 = Lambda.new { |f, list|
|
148
|
+
FOLDL[f, list.head, list.tail]
|
149
|
+
}
|
150
|
+
|
151
|
+
# foldl1' :: (a -> a -> a) -> [a] -> a
|
152
|
+
FOLDL1_ = Lambda.new { |f, list|
|
153
|
+
warn "Method 'foldl1_' is not implemented yet." if $VERBOSE
|
154
|
+
NOT_IMPLEMENTED_YET
|
155
|
+
}
|
156
|
+
|
157
|
+
# foldr :: (a -> b -> b) -> b -> [a] -> b
|
158
|
+
FOLDR = Lambda.new { |f, s, list|
|
159
|
+
#p "foldr #{f.inspect} #{s.inspect} #{list.inspect}"
|
160
|
+
case
|
161
|
+
when list.null : s
|
162
|
+
else f[list.head, FOLDR[f, s, list.tail]]
|
163
|
+
end
|
164
|
+
}
|
165
|
+
|
166
|
+
# foldr1 :: (a -> a -> a) -> [a] -> a
|
167
|
+
FOLDR1 = Lambda.new { |f, list|
|
168
|
+
FOLDR[f, list.head, list.tail]
|
169
|
+
}
|
170
|
+
|
171
|
+
# ** Special folds
|
172
|
+
|
173
|
+
# concat :: [[a]] -> [a]
|
174
|
+
CONCAT = Lambda.new { |list|
|
175
|
+
FOLDR[APPEND, new_list, list]
|
176
|
+
}
|
177
|
+
|
178
|
+
# concatMap :: (a -> [b]) -> [a] -> [b]
|
179
|
+
CONCAT_MAP = Lambda.new { |f, list|
|
180
|
+
FOLDR[APPEND * f, new_list, list]
|
181
|
+
}
|
182
|
+
|
183
|
+
# and :: [Bool] -> Bool
|
184
|
+
AND = Lambda.new { |list|
|
185
|
+
FOLDR[BOOL_AND, true, list]
|
186
|
+
}
|
187
|
+
|
188
|
+
# or :: [Bool] -> Bool
|
189
|
+
OR = Lambda.new { |list|
|
190
|
+
FOLDR[BOOL_OR, false, list]
|
191
|
+
}
|
192
|
+
|
193
|
+
# any :: (a -> Bool) -> [a] -> Bool
|
194
|
+
ANY = OR * MAP
|
195
|
+
|
196
|
+
# all :: (a -> Bool) -> [a] -> Bool
|
197
|
+
ALL = AND * MAP
|
198
|
+
|
199
|
+
# sum :: (Num a) => [a] -> a
|
200
|
+
SUM = NOT_IMPLEMENTED_YET
|
201
|
+
|
202
|
+
# product :: (Num a) => [a] -> a
|
203
|
+
PRODUCT = NOT_IMPLEMENTED_YET
|
204
|
+
|
205
|
+
# maximum :: (Ord a) => [a] -> a
|
206
|
+
MAXIMUM = NOT_IMPLEMENTED_YET
|
207
|
+
|
208
|
+
# minimum :: (Ord a) => [a] -> a
|
209
|
+
MINIMUM = NOT_IMPLEMENTED_YET
|
210
|
+
|
211
|
+
# * Building lists
|
212
|
+
|
213
|
+
# ** Scans
|
214
|
+
|
215
|
+
# scanl :: (a -> b -> a) -> a -> [b] -> [a]
|
216
|
+
SCANL = NOT_IMPLEMENTED_YET
|
217
|
+
|
218
|
+
# scanl1 :: (a -> a -> a) -> [a] -> [a]
|
219
|
+
SCANL1 = NOT_IMPLEMENTED_YET
|
220
|
+
|
221
|
+
# scanr :: (a -> b -> b) -> b -> [a] -> [b]
|
222
|
+
SCANR = NOT_IMPLEMENTED_YET
|
223
|
+
|
224
|
+
# scanr1 :: (a -> a -> a) -> [a] -> [a]
|
225
|
+
SCANR1 = NOT_IMPLEMENTED_YET
|
226
|
+
|
227
|
+
# ** Accumulating maps
|
228
|
+
|
229
|
+
# mapAccumL :: (a -> b -> (a,c)) -> a -> [b] -> (a,[c])
|
230
|
+
MAP_ACCUM_L = NOT_IMPLEMENTED_YET
|
231
|
+
|
232
|
+
# mapAccumR :: (a -> b -> (a,c)) -> a -> [b] -> (a,[c])
|
233
|
+
MAP_ACCUM_R = NOT_IMPLEMENTED_YET
|
234
|
+
|
235
|
+
# ** Infinite lists
|
236
|
+
|
237
|
+
# iterate :: (a -> a) -> a -> [a]
|
238
|
+
ITERATE = NOT_IMPLEMENTED_YET
|
239
|
+
|
240
|
+
# repeat :: a -> [a]
|
241
|
+
REPEAT = NOT_IMPLEMENTED_YET
|
242
|
+
|
243
|
+
# replicate :: Int -> a -> [a]
|
244
|
+
REPLICATE = NOT_IMPLEMENTED_YET
|
245
|
+
|
246
|
+
# cycle :: [a] -> [a]
|
247
|
+
CYCLE = NOT_IMPLEMENTED_YET
|
248
|
+
|
249
|
+
# ** Unfolding
|
250
|
+
|
251
|
+
# unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
|
252
|
+
UNFOLDR = NOT_IMPLEMENTED_YET
|
253
|
+
|
254
|
+
# * Sublists
|
255
|
+
|
256
|
+
# ** Extracting sublists
|
257
|
+
|
258
|
+
# take :: Int -> [a] -> [a]
|
259
|
+
TAKE = NOT_IMPLEMENTED_YET
|
260
|
+
|
261
|
+
# drop :: Int -> [a] -> [a]
|
262
|
+
DROP = NOT_IMPLEMENTED_YET
|
263
|
+
|
264
|
+
# splitAt :: Int -> [a] -> ([a], [a])
|
265
|
+
SPLIT_AT = NOT_IMPLEMENTED_YET
|
266
|
+
|
267
|
+
# takeWhile :: (a -> Bool) -> [a] -> [a]
|
268
|
+
TAKE_WHILE = NOT_IMPLEMENTED_YET
|
269
|
+
|
270
|
+
# dropWhile :: (a -> Bool) -> [a] -> [a]
|
271
|
+
DROP_WHILE = NOT_IMPLEMENTED_YET
|
272
|
+
|
273
|
+
# span :: (a -> Bool) -> [a] -> ([a], [a])
|
274
|
+
SPAN = NOT_IMPLEMENTED_YET
|
275
|
+
|
276
|
+
# break :: (a -> Bool) -> [a] -> ([a], [a])
|
277
|
+
BREAK_ = NOT_IMPLEMENTED_YET
|
278
|
+
|
279
|
+
# group :: Eq a => [a] -> [[a]]
|
280
|
+
GROUP = NOT_IMPLEMENTED_YET
|
281
|
+
|
282
|
+
# inits :: [a] -> [[a]]
|
283
|
+
INITS = NOT_IMPLEMENTED_YET
|
284
|
+
|
285
|
+
# tails :: [a] -> [[a]]
|
286
|
+
TAILS = NOT_IMPLEMENTED_YET
|
287
|
+
|
288
|
+
# ** Predicates
|
289
|
+
|
290
|
+
# isPrefixOf :: (Eq a) => [a] -> [a] -> Bool
|
291
|
+
IS_PREFIX_OF = NOT_IMPLEMENTED_YET
|
292
|
+
|
293
|
+
# isSuffixOf :: (Eq a) => [a] -> [a] -> Bool
|
294
|
+
IS_SUFFIX_OF = NOT_IMPLEMENTED_YET
|
295
|
+
|
296
|
+
# * Searching lists
|
297
|
+
|
298
|
+
# ** Searching by equality
|
299
|
+
|
300
|
+
# elem :: a -> [a] -> Bool
|
301
|
+
ELEM = NOT_IMPLEMENTED_YET
|
302
|
+
|
303
|
+
# notElem :: a -> [a] -> Bool
|
304
|
+
NOT_ELEM = NOT_IMPLEMENTED_YET
|
305
|
+
|
306
|
+
# lookup :: (Eq a) => a -> [(a,b)] -> Maybe b
|
307
|
+
LOOKUP = NOT_IMPLEMENTED_YET
|
308
|
+
|
309
|
+
# ** Searching with a predicate
|
310
|
+
|
311
|
+
# find :: (a -> Bool) -> [a] -> Maybe a
|
312
|
+
FIND = NOT_IMPLEMENTED_YET
|
313
|
+
|
314
|
+
# filter :: (a -> Bool) -> [a] -> [a]
|
315
|
+
FILTER = NOT_IMPLEMENTED_YET
|
316
|
+
|
317
|
+
# partition :: (a -> Bool) -> [a] -> ([a], [a])
|
318
|
+
PARTITION = NOT_IMPLEMENTED_YET
|
319
|
+
|
320
|
+
# * Indexing lists
|
321
|
+
|
322
|
+
# | These functions treat a list @xs@ as a indexed collection,
|
323
|
+
# with indices ranging from 0 to @'length' xs - 1@.
|
324
|
+
|
325
|
+
|
326
|
+
# elemIndex :: (Eq a) => a -> [a] -> Maybe Int
|
327
|
+
ELEM_INDEX = NOT_IMPLEMENTED_YET
|
328
|
+
|
329
|
+
# elemIndices :: (Eq a) => a -> [a] -> [Int]
|
330
|
+
ELEM_INDICES = NOT_IMPLEMENTED_YET
|
331
|
+
|
332
|
+
# findIndex :: (a -> Bool) -> [a] -> Maybe Int
|
333
|
+
FIND_INDEX = NOT_IMPLEMENTED_YET
|
334
|
+
|
335
|
+
# findIndices :: (a -> Bool) -> [a] -> [Int]
|
336
|
+
FIND_INDICES = NOT_IMPLEMENTED_YET
|
337
|
+
|
338
|
+
# * Zipping and unzipping lists
|
339
|
+
|
340
|
+
# zip :: [a] -> [b] -> [(a,b)]
|
341
|
+
ZIP = Lambda.new { |list1, list2|
|
342
|
+
#p "zip #{list1.inspect} #{list2.inspect}"
|
343
|
+
case
|
344
|
+
when (list1.null or list2.null) : []
|
345
|
+
when (LENGTH[list1] == 1 or LENGTH[list2] == 1) :
|
346
|
+
new_list.cons(new_list.cons(list2.head).cons(list1.head))
|
347
|
+
else
|
348
|
+
ZIP[list1.tail, list2.tail].cons(new_list.cons(list2.head).cons(list1.head))
|
349
|
+
end
|
350
|
+
}
|
351
|
+
|
352
|
+
# zip3
|
353
|
+
ZIP3 = NOT_IMPLEMENTED_YET
|
354
|
+
|
355
|
+
# zip4, zip5, zip6, zip7
|
356
|
+
ZIP4 = NOT_IMPLEMENTED_YET
|
357
|
+
|
358
|
+
# zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
|
359
|
+
ZIP_WITH = NOT_IMPLEMENTED_YET
|
360
|
+
|
361
|
+
# zipWith3
|
362
|
+
ZIP_WITH3 = NOT_IMPLEMENTED_YET
|
363
|
+
|
364
|
+
# zipWith4, zipWith5, zipWith6, zipWith7
|
365
|
+
ZIP_WITH4 = NOT_IMPLEMENTED_YET
|
366
|
+
|
367
|
+
# unzip :: [(a,b)] -> ([a],[b])
|
368
|
+
UNZIP = NOT_IMPLEMENTED_YET
|
369
|
+
|
370
|
+
# unzip3
|
371
|
+
UNZIP3 = NOT_IMPLEMENTED_YET
|
372
|
+
|
373
|
+
# unzip4, unzip5, unzip6, unzip7
|
374
|
+
UNZIP4 = NOT_IMPLEMENTED_YET
|
375
|
+
|
376
|
+
# * Special lists
|
377
|
+
|
378
|
+
# ** Functions on strings
|
379
|
+
|
380
|
+
# lines :: String -> [String]
|
381
|
+
LINES = NOT_IMPLEMENTED_YET
|
382
|
+
|
383
|
+
# words :: String -> [String]
|
384
|
+
WORDS = NOT_IMPLEMENTED_YET
|
385
|
+
|
386
|
+
# unlines :: [String] -> String
|
387
|
+
UNLINES = NOT_IMPLEMENTED_YET
|
388
|
+
|
389
|
+
# unwords :: [String] -> String
|
390
|
+
UNWORDS = NOT_IMPLEMENTED_YET
|
391
|
+
|
392
|
+
# ** "Set" operations
|
393
|
+
|
394
|
+
# nub :: (Eq a) => [a] -> [a]
|
395
|
+
NUB = NOT_IMPLEMENTED_YET
|
396
|
+
|
397
|
+
# delete :: (Eq a) => a -> [a] -> [a]
|
398
|
+
DELETE = NOT_IMPLEMENTED_YET
|
399
|
+
|
400
|
+
# union :: (Eq a) => [a] -> [a] -> [a]
|
401
|
+
UNION = NOT_IMPLEMENTED_YET
|
402
|
+
|
403
|
+
# intersect :: (Eq a) => [a] -> [a] -> [a]
|
404
|
+
INTERSECT = NOT_IMPLEMENTED_YET
|
405
|
+
|
406
|
+
# ** Ordered lists
|
407
|
+
|
408
|
+
# sort :: (Ord a) => [a] -> [a]
|
409
|
+
SORT = NOT_IMPLEMENTED_YET
|
410
|
+
|
411
|
+
# insert :: (Ord a) => a -> [a] -> [a]
|
412
|
+
INSERT = NOT_IMPLEMENTED_YET
|
413
|
+
|
414
|
+
end # Prelude
|