我在翻译中写了一个类似Scheme的程序。类似Scheme的解释器应该与任何实现IEnumerable的对象一起工作,这似乎很自然。
解释器不允许突变 - 没有暴露副作用的功能。
因为IEnumerable不可复制,(参见here),我无法使用car和cdr有效地在列表上实现迭代。
为了让任何“更高阶”的东西更有效率,我必须为解释器实现一些原语作为C#builtins。
到目前为止,我已将以下“原语”实现为C#内置函数:
但我怀疑,例如,我可能会使用map和foldr的组合来实现“过滤器”。
我需要公开为“builtins”的最小原语集是什么,这样我可以在IEnumerable实例上实现任何其他功能,而不会产生过多的运行时或空间成本,而且不必引入变异?
答案 0 :(得分:2)
System.Linq名称空间中已经存在所有函数。
你会发现更多。例如
SelectMany = map + map + flatten GroupBy =分区
remq和朋友可以在过滤器方面完成。
<强>更新强>
与普通的Scheme定义不同,这些显然只占用1个列表参数。
答案 1 :(得分:2)
您不必严格要求map
成为基元,因为您可以使用foldr
来定义它。
示例(在Haskell中):
map f = foldr (\a b->f a:b) []
这实际上是mapcar
而非map
,但由于map
不可用,因此很难在Haskell中表达完整的apply
。
更完整的示例(在Scheme中):
(define (mapcar f l)
(foldr (lambda (x t) (cons (f x) t)) ‛() l))
(define (heads ls) (mapcar car ls))
(define (tails ls) (mapcar cdr ls))
(define (any-null? ls) (foldr or? ﹟f (mapcar null? ls)))
(define (map f . ls)
(if (any-null? ls)
‛()
(cons (apply f (heads ls)) (apply map f (tails ls)))))
如果您没有car
和cdr
,还有其他方法可以定义它们,例如如果你有闭合&amp;您的语言中的变量:
(define (car a) (foldr (lambda (x y) x) ﹟f a))
(define (cdr a)
(let ((prev ‛())
(tmp #f))
(foldr (lambda (h t) (set! tmp (cons h t)) (set! prev t) tmp)
‛()
a)
prev))
答案 2 :(得分:0)
我不太确定你的序列计算的功能是什么,但是连接操作(即展平嵌套序列)也可能非常有用。看看Haskell的列表理解是如何被人们去了解的原因。