在scheme中自己实现list comprehension

scheme并不提供list comprehension特性,但是

 在stackoverflow上可以看到几个提供list comprehension的库(Swindle已经是个语言了):

 

  • Swindle is primarily a CLOS emulator library, but it has list comprehensions too. I've used them, they're convenient, but the version I used was buggy and incomplete. (I just needed generic functions.)
  • However, you probably want SRFI-42. I haven't used it, but it HAS to have fewer bugs than the Swindle list comprehensions.

可是两个库提供的list comprehension所用的语法我看着都不爽......肿木办?自己写个呗:scheme is a programable programming language!

 

(define (flat-map f xs)
  (apply append (map f xs)))

(define-syntax list-of
  (syntax-rules (<- :=)
    [(_ expr (v <- a-list) rule ...);folk
     (flat-map (lambda (v) (list-of expr rule ...)) a-list)]
    [(_ expr (v := v-expr) rule ...)
     (let ([v v-expr]) 
       (list-of expr rule ...))]
    [(_ expr P rule ...);filter(prune)
     (if P 
         (list-of expr rule ...) 
         '())]
    [(_ expr);base case
     (cons expr '())]))

 

 这个list-of隐含了对表达式从左到右的处理顺序.

来个辅助函数range,生成从low到up的整数list:

 

(define (range low up)
  (if (> low up) '() (cons low (range (+ 1 low) up)))) 

 >(range 1 10)

=>(1 2 3 4 5 6 7 8 9 10) 

 

比如求边长整数且最大边长不超过100的所有直角三角形 : 

[list-of (list x y z) [x <- (range 1 100)] [y <- (range 1 100)] [z <- (range 1 100)] 
           (< x y z)      (= (* z z) (+ (* x x) (* y y)))]

 结果:

{{3 4 5}

 {5 12 13}
 {6 8 10}
 {7 24 25}
 {8 15 17}
 {9 12 15}
 {9 40 41}
 {10 24 26}
 {11 60 61}
 {12 16 20}
 {12 35 37}
 {13 84 85}
 {14 48 50}
 {15 20 25}
 {15 36 39}
 {16 30 34}
 {16 63 65}
 {18 24 30}
 {18 80 82}
 {20 21 29}
 {20 48 52}
 {21 28 35}
 {21 72 75}
 {24 32 40}
 {24 45 51}
 {24 70 74}
 {25 60 65}
 {27 36 45}
 {28 45 53}
 {28 96 100}
 {30 40 50}
 {30 72 78}
 {32 60 68}
 {33 44 55}
 {33 56 65}
 {35 84 91}
 {36 48 60}
 {36 77 85}
 {39 52 65}
 {39 80 89}
 {40 42 58}
 {40 75 85}
 {42 56 70}
 {45 60 75}
 {48 55 73}
 {48 64 80}
 {51 68 85}
 {54 72 90}
 {57 76 95}
 {60 63 87}
 {60 80 100}
 {65 72 97}}

 

但是这样做是先生成100*100*100的list然后在检查过滤,效率太低,可以调整一下表达式顺序:

(list-of (list x y z) 
         [x <- (range 1 100)]
         [y <- (range 1 100)]
         (< x y);prune,z is not bound yet
         [z := (+ (* x x) (* y y))];a more effect but less decarative way
         (<= z 100));filte 

  这下快多了,但是这些顺序细节不应该暴露出来,应该再写个partial evaluator根据变量出现的先后自动调整表达式顺序,然后在交给list-of去计算.以后蛋疼的时候再弄吧......

 还有如果再蛋疼,可以把它搞成兼容惰性求值的,[x <- a-generator]酱紫.

posted @ 2012-03-31 23:13  硅胶鱼  阅读(712)  评论(0编辑  收藏  举报