2

我了解 Haskell 语法。

我想咖喱(部分应用)一个名为“play-note”的函数,并“手动”传递一个参数,第二个参数带有地图。

如果我可以用 Haskell 编写它,我会说:

playNote :: Time -> Instrument -> Int -> Int -> Int -> Int -> Music -- made up, but just to give you an idea

notes = [46, 47, 35, 74]  
loopGo = True

loop time = do mapM_ (playNote' time) notes 
               if loopGo then (loop (time+(second/2))) else return () -- time element removed
playNote' time pitch = playNote time drums pitch 80 11025 9 -- ignore extra args

在 Scheme 中,这是我所拥有的最好的:

(define notes '(46 47 35 74))  
(define *loop-go* #t)
(define play-note-prime  
   (lambda (time2)  
      (lambda (pitch)  
         (play-note time2 drums pitch 80 11025 9))))  ; drums is another variable
(define loop  
   (lambda (time)  
      (map (play-note-prime time) notes)  
      (if *loop-go*  
          (callback (+ time (/ *second* 2)) 'loop (+ time (/ second 2)))))) ; time element is more sophisticated here

Scheme 版本“编译”,但没有按照我的预期做(咖喱第一个参数,然后是第二个)。帮助?谢谢!

编辑:
我的问题的本质是无法定义一个接受两个参数的函数,以使以下代码产生正确的结果:

map ({some function} {some value; argument 1}) {some list; each element will be an argument 2}
4

3 回答 3

2

回答我自己的问题:

该函数需要定义为“零碎”地接受参数:换句话说,它并不是真正的柯里化。我在上面尝试过,但没有做对。

部分应用的函数需要被描述为一个 lambda 或 lambda 链,每个都准确地接受将要传递的参数的数量(按接收时间的降序排列)。

一个工作示例:

(define nums '(3 3 1 2))
(define f
   (lambda (num1)
      (lambda (num2)
         (expt num1 num2))))
(define ans (map (f 5) nums))
(print ans)

将 f 定义为接受所有参数将不起作用:

(define f
   (lambda (num1 num2)
      (expt num1 num2))) ; Can't be curried
于 2011-08-24T08:05:13.780 回答
1

你是对的——在方案中做到这一点的一种方法是手动创建 lambdas。这当然会很痛苦,以一种通用的、正确的方式实现,即检查参数的数量(不希望有太多!)。

以下是 Clojure(另一种 LISP 方言)是如何做到的:

http://clojuredocs.org/clojure_core/clojure.core/partial

来源丑吗?也许。它有效吗?当然。

于 2011-08-26T17:41:39.973 回答
1

除非我遗漏了什么,否则srfi-26 的cutcute不会提供您需要的东西吗?然后它只是您的方案实施是否提供它的问题(我认为大多数人都提供)

于 2011-09-10T22:08:30.853 回答