prelude 0.0.3 → 0.0.5
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.
- 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
|