Clojure,文字向量与函数结果不同



我正在尝试使用clojure的泛音库制作音乐。为了产生有趣的声音,加法合成很有用,这意味着我采用多个频率的正弦振荡器并简单地添加它们。在泛音中,要创建一个合成器,它意识到这一点,我可以写:

(definst myinst [freq 100]
  (* 0.2 (reduce + (map sin-osc [101.0 100 99.0]))))

为了更好地重用,我编写了一个函数,它采用一个频率并返回包含所有这些频率的列表,您可以在代码片段中看到:

(defn split-freq [freq]
  (apply vector (map #(* freq %) [1.01 1 0.99])))

执行(split-freq 100)时,REPL 给我以下内容:

[101.0 100 99.0]

这与输入完全相同,我提供了上面的地图功能。事实上,我复制了结果。现在,我试试这个:

(definst myinst [freq 100]
  (* 0.2 (reduce + (map sin-osc (split-freq freq)))))

不幸的是,REPL告诉我,我做错了:

CompilerException java.lang.ClassCastException: 
overtone.sc.machinery.ugen.sc_ugen.ControlProxy cannot be cast to java.lang.Number, 
compiling:(form-init1807789563491679853.clj:1)

但是这段代码工作正常:

(definst myinst [freq 100]
  (* 0.2 (reduce + (map sin-osc (apply vector (map #(* freq %) [1.01 1 0.99]))))))

虽然,我只是输入了函数定义。

我想我主要缺乏理解。我想,如果其中一个版本有效,那么其他版本也必须有效。

我的问题是:为什么我的"改进"版本不起作用?为什么第一个代码段有效?如何规避此行为?

Clojure 1.3.0
Overtone 0.8
(use 'overtone.core)

ups,你是对的,我不明白 Noisesmith 的评论。确实,您不能直接在函数中使用此值"freq",因为此值在函数需要它时(宏执行之前)未绑定

所以这里是这个问题的解决方法,也使用 let 形式,它没有那么优雅,可以制作自己的宏,但可以工作

(defn myinst [inst-name]
  (let [the-freq 100]
   (definst inst-name [freq the-freq] (* 0.2 (reduce + (map sin-osc (split-freq the-freq)))))))

您可以作为普通函数执行

((myinst "my-instrument"))

我希望对您有所帮助

胡安


以前的评论,现在无效的响应

也许您在改进版本中的参数值声明中犯了错误

那是你的代码

(definst myinst [freq 100]
  (* 0.2 (reduce + (map sin-osc (split-freq freq)))))

而且,就像在 clojure 中一样,您不能将默认值分配给参数函数,例如,如果您使用 let 表单来分配默认值,您的改进版本将起作用

(definst myinst []
  (let [freq 100]
    (* 0.2 (reduce + (map sin-osc (split-freq freq))))))  

相关内容

  • 没有找到相关文章

最新更新