prelude 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/TODO ADDED
@@ -0,0 +1,6 @@
1
+ = TODO list
2
+
3
+ $Id: TODO 2 2006-08-25 00:11:17Z prelude $
4
+
5
+ Please refer to the task list on Rubyforge site for all outstanding tasks, see
6
+ http://rubyforge.org/pm/?group_id=2096
@@ -0,0 +1,66 @@
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 program is free software; you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation; either version 2 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # This program 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
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License along
20
+ # with this program; if not, write to the Free Software Foundation, Inc.,
21
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
+ #++
23
+ #
24
+ # $Id: prelude.rb 2 2006-08-25 00:11:17Z prelude $
25
+
26
+ $:.unshift(File.dirname(__FILE__))
27
+
28
+ require 'prelude/list'
29
+ require 'prelude/tuple'
30
+ require 'prelude/monad'
31
+
32
+ module Prelude
33
+ VERSION='0.0.1'
34
+ end # Prelude
35
+
36
+ class Symbol
37
+
38
+ # See http://blogs.pragprog.com/cgi-bin/pragdave.cgi/Tech/Ruby/ToProc.rdoc for the detailed discussion
39
+ def to_proc
40
+ proc { |obj, *args| obj.send(self, *args) }
41
+ end
42
+
43
+ def curry(one, *args)
44
+ proc { |*args| self.to_proc.call(one, *args) }
45
+ end
46
+
47
+ end # Symbol
48
+
49
+ class Proc
50
+
51
+ # See also http://rubyforge.org/projects/rubymurray/ for an
52
+ # elaborate port of Perl's Sub::Curry library
53
+ def curry(one, *args)
54
+ proc{ |*args| self.call(one, *args)}
55
+ end
56
+
57
+ # This is will serve as an infix composition operator
58
+ def <<(*args)
59
+ if (1==args.length) && args[0].is_a?(Proc)
60
+ proc {|*a| self.call(args[0].call(*a)) }
61
+ else
62
+ self.call(*args.flatten)
63
+ end
64
+ end
65
+
66
+ end # Proc
@@ -0,0 +1,572 @@
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 program is free software; you can redistribute it and/or modify
10
+ # it under the terms of the GNU General Public License as published by
11
+ # the Free Software Foundation; either version 2 of the License, or
12
+ # (at your option) any later version.
13
+ #
14
+ # This program 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
17
+ # GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License along
20
+ # with this program; if not, write to the Free Software Foundation, Inc.,
21
+ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
+ #++
23
+
24
+ module Prelude
25
+
26
+ # $Id: list.rb 2 2006-08-25 00:11:17Z prelude $
27
+ #
28
+ # This code is inspired in part by Hipster, <hipster xs4all.nl> (a.k.a. Michel
29
+ # van de Ven), and his original sketch was initially located at
30
+ # http://www.xs4all.nl/~hipster/lib/ruby/haskell
31
+ #
32
+ # This eventually needs to be implemented with lazy lists, see
33
+ # http://lazylist.rubyforge.org for details
34
+ #
35
+ # I used the signatures of Haskell's List.hs file in order not to forget to implement
36
+ # the functions defined there and to remind of what was intended.
37
+ class List < Array
38
+
39
+ # Array compatibility functions
40
+ alias array_plus +
41
+
42
+ def +(o)
43
+ List.new(self.array_plus(o))
44
+ end
45
+
46
+ # , head -- :: [a] -> a
47
+ def head
48
+ self[0]
49
+ end
50
+
51
+ # , last -- :: [a] -> a
52
+ # already defined by the Array
53
+
54
+ # , tail -- :: [a] -> [a]
55
+ def tail
56
+ self[1..-1]
57
+ end
58
+
59
+ # , init -- :: [a] -> [a]
60
+ def init
61
+ self[0..-2]
62
+ end
63
+
64
+ # , null -- :: [a] -> Bool
65
+ def null
66
+ size == 0
67
+ end
68
+
69
+ # , length -- :: [a] -> Int
70
+ # Implemented by Array
71
+
72
+ # -- * List transformations
73
+ # , map -- :: (a -> b) -> [a] -> [b]
74
+ # Implemented by Array
75
+
76
+ # , reverse -- :: [a] -> [a]
77
+ # Implemented by Array
78
+
79
+ # , intersperse -- :: a -> [a] -> [a]
80
+ def intersperse
81
+ warn "Method 'intersperse' is not implemented yet." if $VERBOSE
82
+ return []
83
+ end
84
+
85
+ # , transpose -- :: [[a]] -> [[a]]
86
+ # Implemented by Array
87
+
88
+ # -- * Reducing lists (folds)
89
+
90
+ # , foldl -- :: (a -> b -> a) -> a -> [b] -> a
91
+
92
+ # Classic recursive functional definition causes stack overflow for
93
+ # arrays of any usable size... So don't use it, it's here for
94
+ # demonstration purposes only
95
+ def f_foldl(s, &block)
96
+ empty? ? s : tail.f_foldl(block.call(s, head), &block)
97
+ end
98
+
99
+ # This is a more pedestrian iterative version.
100
+ def foldl(s, &block)
101
+ inject(s){ |a,b| block.call(a,b) }
102
+ end
103
+
104
+ # , foldl' -- :: (a -> b -> a) -> a -> [b] -> a
105
+ def foldl_
106
+ warn "Method 'foldl_' is not implemented yet." if $VERBOSE
107
+ return []
108
+ end
109
+
110
+ # , foldl1 -- :: (a -> a -> a) -> [a] -> a
111
+ def foldl1(&block)
112
+ tail.foldl(head, &block)
113
+ end
114
+
115
+ # , foldl1' -- :: (a -> a -> a) -> [a] -> a
116
+ def foldl1_
117
+ warn "Method 'foldl1_' is not implemented yet." if $VERBOSE
118
+ return []
119
+ end
120
+
121
+ # , foldr -- :: (a -> b -> b) -> b -> [a] -> b
122
+ def foldr(s, &block)
123
+ inject(s){ |a,b| block.call(b, a) }
124
+ end
125
+
126
+ # , foldr1 -- :: (a -> a -> a) -> [a] -> a
127
+ def foldr1(&block)
128
+ tail.foldr(head, &block)
129
+ end
130
+
131
+ # -- ** Special folds
132
+
133
+ # , concat -- :: [[a]] -> [a]
134
+ # Implemented by Array but semantics is different
135
+ def concat
136
+ flatten
137
+ end
138
+
139
+
140
+ # , concatMap -- :: (a -> [b]) -> [a] -> [b]
141
+ def concat_map
142
+ warn "Method 'concatMap' is not implemented yet." if $VERBOSE
143
+ return []
144
+ end
145
+ alias concatMap concat_map
146
+
147
+ # , and -- :: [Bool] -> Bool
148
+ def and
149
+ foldr(true){|x,y| x && y}
150
+ end
151
+
152
+ # , or -- :: [Bool] -> Bool
153
+ def or
154
+ foldr(false){|x,y| (x || y)}
155
+ end
156
+
157
+ # , any -- :: (a -> Bool) -> [a] -> Bool
158
+ def any(&block)
159
+ each{|e| return true if block.call(e)}
160
+ return false
161
+ end
162
+
163
+ # , all -- :: (a -> Bool) -> [a] -> Bool
164
+ def all(&block)
165
+ each{|e| return false unless block.call(e)}
166
+ return true
167
+ end
168
+
169
+ # , sum -- :: (Num a) => [a] -> a
170
+ def sum
171
+ warn "Method 'sum' is not implemented yet." if $VERBOSE
172
+ return []
173
+ end
174
+
175
+ # , product -- :: (Num a) => [a] -> a
176
+ def product
177
+ warn "Method 'product' is not implemented yet." if $VERBOSE
178
+ return []
179
+ end
180
+
181
+ # , maximum -- :: (Ord a) => [a] -> a
182
+ def maximum
183
+ warn "Method 'maximum' is not implemented yet." if $VERBOSE
184
+ return []
185
+ end
186
+
187
+ # , minimum -- :: (Ord a) => [a] -> a
188
+ def minimum
189
+ warn "Method 'minimum' is not implemented yet." if $VERBOSE
190
+ return []
191
+ end
192
+
193
+
194
+ # -- * Building lists
195
+
196
+ # -- ** Scans
197
+ # , scanl -- :: (a -> b -> a) -> a -> [b] -> [a]
198
+ def scanl(s, &block)
199
+ inject([s]){ |a,b| a << block.call(a.last,b) }
200
+ end
201
+
202
+ # , scanl1 -- :: (a -> a -> a) -> [a] -> [a]
203
+ def scanl1(&block)
204
+ tail.scanl(head, &block)
205
+ end
206
+
207
+ # , scanr -- :: (a -> b -> b) -> b -> [a] -> [b]
208
+ def scanr(s, &block)
209
+ inject([s]){ |a,b| a << block.call(b, a.last) }
210
+ end
211
+
212
+ # , scanr1 -- :: (a -> a -> a) -> [a] -> [a]
213
+ def scanr1(&block)
214
+ tail.scanr(head, &block)
215
+ end
216
+
217
+
218
+ # -- ** Accumulating maps
219
+ # , mapAccumL -- :: (a -> b -> (a,c)) -> a -> [b] -> (a,[c])
220
+ def map_accum_l
221
+ warn "Method 'map_accum_l' is not implemented yet." if $VERBOSE
222
+ return []
223
+ end
224
+ alias mapAccumL map_accum_l
225
+
226
+ # , mapAccumR -- :: (a -> b -> (a,c)) -> a -> [b] -> (a,[c])
227
+ def map_accum_r
228
+ warn "Method 'map_accum_r' is not implemented yet." if $VERBOSE
229
+ return []
230
+ end
231
+ alias mapAccumR map_accum_r
232
+
233
+
234
+ # -- ** Infinite lists
235
+ # , iterate -- :: (a -> a) -> a -> [a]
236
+ def iterate
237
+ warn "Method 'iterate' is not implemented yet." if $VERBOSE
238
+ return []
239
+ end
240
+
241
+ # , repeat -- :: a -> [a]
242
+ def repeat
243
+ warn "Method 'repeat' is not implemented yet." if $VERBOSE
244
+ return []
245
+ end
246
+
247
+ # , replicate -- :: Int -> a -> [a]
248
+ def replicate
249
+ warn "Method 'replicate' is not implemented yet." if $VERBOSE
250
+ return []
251
+ end
252
+
253
+ # , cycle -- :: [a] -> [a]
254
+ def cycle
255
+ warn "Method 'cycle' is not implemented yet." if $VERBOSE
256
+ return []
257
+ end
258
+
259
+
260
+ # -- ** Unfolding
261
+ # , unfoldr -- :: (b -> Maybe (a, b)) -> b -> [a]
262
+ def unfoldr
263
+ warn "Method 'unfoldr' is not implemented yet." if $VERBOSE
264
+ return []
265
+ end
266
+
267
+
268
+ # -- * Sublists
269
+
270
+ # -- ** Extracting sublists
271
+ # , take -- :: Int -> [a] -> [a]
272
+ def take(n)
273
+ self[0..(n-1)]
274
+ end
275
+
276
+ # , drop -- :: Int -> [a] -> [a]
277
+ def drop(n)
278
+ self[n..-1]
279
+ end
280
+
281
+ # , splitAt -- :: Int -> [a] -> ([a], [a])
282
+ def split_at(n)
283
+ [take(n), drop(n)]
284
+ end
285
+ alias splitAt split_at
286
+
287
+ # , takeWhile -- :: (a -> Bool) -> [a] -> [a]
288
+ def take_while
289
+ r = []
290
+ each{ |e|
291
+ break unless yield(e)
292
+ r << e
293
+ }
294
+ r
295
+ end
296
+ alias takeWhile take_while
297
+
298
+ # , dropWhile -- :: (a -> Bool) -> [a] -> [a]
299
+ def drop_while
300
+ r = []
301
+ each{ |e|
302
+ next if yield(e)
303
+ r << e
304
+ }
305
+ r
306
+ end
307
+ alias dropWhile drop_while
308
+
309
+ # , span -- :: (a -> Bool) -> [a] -> ([a], [a])
310
+ def span(&block)
311
+ [take_while(&block), drop_while(&block)]
312
+ end
313
+
314
+ # , break -- :: (a -> Bool) -> [a] -> ([a], [a])
315
+ def break
316
+ warn "Method 'break' is not implemented yet." if $VERBOSE
317
+ return []
318
+ end
319
+
320
+ # , group -- :: Eq a => [a] -> [[a]]
321
+ def group
322
+ warn "Method 'group' is not implemented yet." if $VERBOSE
323
+ return []
324
+ end
325
+
326
+ # , inits -- :: [a] -> [[a]]
327
+ def inits
328
+ warn "Method 'inits' is not implemented yet." if $VERBOSE
329
+ return []
330
+ end
331
+
332
+ # , tails -- :: [a] -> [[a]]
333
+ def tails
334
+ warn "Method 'tails' is not implemented yet." if $VERBOSE
335
+ return []
336
+ end
337
+
338
+ # -- ** Predicates
339
+ # , isPrefixOf -- :: (Eq a) => [a] -> [a] -> Bool
340
+ def is_prefix_of
341
+ warn "Method 'is_prefix_of' is not implemented yet." if $VERBOSE
342
+ return []
343
+ end
344
+ alias isPrefixOf is_prefix_of
345
+
346
+ # , isSuffixOf -- :: (Eq a) => [a] -> [a] -> Bool
347
+ def is_suffix_of
348
+ warn "Method 'is_suffix_of' is not implemented yet." if $VERBOSE
349
+ return []
350
+ end
351
+ alias isSuffixOf is_suffix_of
352
+
353
+ # -- * Searching lists
354
+
355
+ # -- ** Searching by equality
356
+ # , elem -- :: a -> [a] -> Bool
357
+ def elem
358
+ warn "Method 'elem' is not implemented yet." if $VERBOSE
359
+ return []
360
+ end
361
+
362
+ # , notElem -- :: a -> [a] -> Bool
363
+ def not_elem
364
+ warn "Method 'not_elem' is not implemented yet." if $VERBOSE
365
+ return []
366
+ end
367
+ alias notElem not_elem
368
+
369
+ # , lookup -- :: (Eq a) => a -> [(a,b)] -> Maybe b
370
+ def lookup
371
+ warn "Method 'lookup' is not implemented yet." if $VERBOSE
372
+ return []
373
+ end
374
+
375
+ # -- ** Searching with a predicate
376
+ # , find -- :: (a -> Bool) -> [a] -> Maybe a
377
+ # Implemented by Array
378
+
379
+ # , filter -- :: (a -> Bool) -> [a] -> [a]
380
+ def filter
381
+ warn "Method 'filter' is not implemented yet." if $VERBOSE
382
+ return []
383
+ end
384
+
385
+ # , partition -- :: (a -> Bool) -> [a] -> ([a], [a])
386
+ # Implemented by Array
387
+
388
+
389
+ # -- * Indexing lists
390
+ # -- | These functions treat a list @xs@ as a indexed collection,
391
+ # -- with indices ranging from 0 to @'length' xs - 1@.
392
+
393
+ # , (!!) -- :: [a] -> Int -> a
394
+ # Don't know how to implement it in Ruby
395
+
396
+
397
+ # , elemIndex -- :: (Eq a) => a -> [a] -> Maybe Int
398
+ def elem_index
399
+ warn "Method 'elem_index' is not implemented yet." if $VERBOSE
400
+ return []
401
+ end
402
+ alias elemIndex elem_index
403
+
404
+ # , elemIndices -- :: (Eq a) => a -> [a] -> [Int]
405
+ def elem_indices
406
+ warn "Method 'elem_indices' is not implemented yet." if $VERBOSE
407
+ return []
408
+ end
409
+ alias elemIndices elem_indices
410
+
411
+ # , findIndex -- :: (a -> Bool) -> [a] -> Maybe Int
412
+ def find_index
413
+ warn "Method 'find_index' is not implemented yet." if $VERBOSE
414
+ return []
415
+ end
416
+ alias findIndex find_index
417
+
418
+ # , findIndices -- :: (a -> Bool) -> [a] -> [Int]
419
+ def find_indices
420
+ warn "Method 'find_indices' is not implemented yet." if $VERBOSE
421
+ return []
422
+ end
423
+ alias findIndices find_indices
424
+
425
+
426
+ # -- * Zipping and unzipping lists
427
+
428
+ # , zip -- :: [a] -> [b] -> [(a,b)]
429
+ # Implemented by Array
430
+
431
+ # , zip3
432
+ def zip3
433
+ warn "Method 'zip3' is not implemented yet." if $VERBOSE
434
+ return []
435
+ end
436
+
437
+ # , zip4, zip5, zip6, zip7
438
+ def zip4
439
+ warn "Method 'zip4' is not implemented yet." if $VERBOSE
440
+ return []
441
+ end
442
+
443
+
444
+ # , zipWith -- :: (a -> b -> c) -> [a] -> [b] -> [c]
445
+ def zip_with
446
+ warn "Method 'zip_with' is not implemented yet." if $VERBOSE
447
+ return []
448
+ end
449
+ alias zipWith zip_with
450
+
451
+ # , zipWith3
452
+ def zip_with3
453
+ warn "Method 'zip_with3' is not implemented yet." if $VERBOSE
454
+ return []
455
+ end
456
+ alias zipWith3 zip_with3
457
+
458
+ # , zipWith4, zipWith5, zipWith6, zipWith7
459
+ def zip_with4
460
+ warn "Method 'zip_with4' is not implemented yet." if $VERBOSE
461
+ return []
462
+ end
463
+ alias zipWith4 zip_with4
464
+
465
+
466
+ # , unzip -- :: [(a,b)] -> ([a],[b])
467
+ def unzip
468
+ warn "Method 'unzip' is not implemented yet." if $VERBOSE
469
+ return []
470
+ end
471
+
472
+ # , unzip3
473
+ def unzip3
474
+ warn "Method 'unzip3' is not implemented yet." if $VERBOSE
475
+ return []
476
+ end
477
+
478
+ # , unzip4, unzip5, unzip6, unzip7
479
+ def unzip4
480
+ warn "Method 'unzip4' is not implemented yet." if $VERBOSE
481
+ return []
482
+ end
483
+
484
+
485
+ # -- * Special lists
486
+
487
+ # -- ** Functions on strings
488
+ # , lines -- :: String -> [String]
489
+ def lines
490
+ warn "Method 'lines' is not implemented yet." if $VERBOSE
491
+ return []
492
+ end
493
+
494
+ # , words -- :: String -> [String]
495
+ def words
496
+ warn "Method 'words' is not implemented yet." if $VERBOSE
497
+ return []
498
+ end
499
+
500
+ # , unlines -- :: [String] -> String
501
+ def unlines
502
+ warn "Method 'unlines' is not implemented yet." if $VERBOSE
503
+ return []
504
+ end
505
+
506
+ # , unwords -- :: [String] -> String
507
+ def unwords
508
+ warn "Method 'unwords' is not implemented yet." if $VERBOSE
509
+ return []
510
+ end
511
+
512
+
513
+ # -- ** \"Set\" operations
514
+
515
+ # , nub -- :: (Eq a) => [a] -> [a]
516
+ def nub
517
+ warn "Method 'nub' is not implemented yet." if $VERBOSE
518
+ return []
519
+ end
520
+
521
+
522
+ # , delete -- :: (Eq a) => a -> [a] -> [a]
523
+ # Implemented by Array but semantics is different
524
+ def delete(o)
525
+ warn "Method 'delete' is not implemented yet." if $VERBOSE
526
+ return []
527
+ end
528
+
529
+
530
+ # , (\\) -- :: (Eq a) => [a] -> [a] -> [a]
531
+ # Don't know how to implement it in Ruby
532
+
533
+
534
+ # , union -- :: (Eq a) => [a] -> [a] -> [a]
535
+ def union
536
+ warn "Method 'union' is not implemented yet." if $VERBOSE
537
+ return []
538
+ end
539
+
540
+ # , intersect -- :: (Eq a) => [a] -> [a] -> [a]
541
+ def intersect
542
+ warn "Method 'intersect' is not implemented yet." if $VERBOSE
543
+ return []
544
+ end
545
+
546
+
547
+ # -- ** Ordered lists
548
+ # , sort -- :: (Ord a) => [a] -> [a]
549
+ # Implemented by Array
550
+
551
+ # , insert -- :: (Ord a) => a -> [a] -> [a]
552
+ # Implemented by Array but semantics is different
553
+ def insert(o)
554
+ warn "Method 'insert' is not implemented yet." if $VERBOSE
555
+ return []
556
+ end
557
+
558
+
559
+ # def functional_fold(st, &op)
560
+ # f = proc { |s, a|
561
+ # if a.empty? then
562
+ # proc { s }
563
+ # else
564
+ # f.call(op.call(s, a[0]), a.slice(1, a.length-1))
565
+ # end
566
+ # }
567
+ # f.call(st, self)
568
+ # end
569
+
570
+ end # List
571
+
572
+ end # Prelude