我正在通过编写OSC音乐音序器来学习Haskell,以便将它与SuperCollider一起使用。但是因为我想用它制作相当复杂的东西,它会像编程语言一样工作,你可以声明变量和定义函数,这样你就可以用算法的方式编写音乐。语法是不寻常的,因为我们编码序列,有时一个小节将引用最后一个小节(类似“再次播放最后一个和弦,但上面的第五个”)。 我对自己的解释感到不满意,但这是我能做到的最好,不会太过技术化。
无论如何,我现在正在编码的是该语言的解析器,到目前为止无状态,但现在我需要一些方法来实现一个增长的声明变量列表并使用[("key","value")]
方式的字典相似,所以我可以添加新值,因为我逐条解析吧。
我知道这涉及monad,我还不太了解它,但我需要一些足够有意义的东西来开始玩它们,否则我发现原始理论有点过于粗糙。
那么什么是干净简单的开始方式? 如果问题太长,谢谢,抱歉。
编辑事物的运作方式:
我们在主解析函数中输入一个字符串,比方说
"afunction(3) ; anotherone(1) + [3,2,1]"
我们首先识别闭包,然后识别各种字符(字母,数字等)并将它们组合在一起,这样我们得到一个列表:
[("word","afunction"),("parenth","(3)"),("space"," "),("semicolon",";"),("space"," "),("word","anotherone"),("parenth","(1)"),("space"," "),("opadd","+"),("space"," "),("bracket","[3,2,1]")]
然后我们使用一个函数,用它们占用的原始字符串的索引标记所有这些元组,如:
[("word","afunction",(0,8)),("parenth","(3)",(9,11)),("space"," ",(12,13)) ...]
然后在一个条形列表中剪切它,在我的语言中使用分号分隔,然后在笔记中使用逗号分隔。
现在我正处于这些函数应该按顺序执行的阶段,但由于其中一些函数正在读取或修改先前声明的值,因此我需要跟踪该更改。例如,假设函数f(x)
将最后一个音符的音高移动x
半音,所以
f(9), -- from an original base value of 0 (say that's an A440) we go to 9
f(-2), -- 9-2 = 7, so a fifth from A
f(-3); -- 9-2-3, a minor third down from the last value.
等
但有时它会比这更复杂,不要让我解释我是如何让你死的。
答案 0 :(得分:4)
您可以创建一个新列表,其中包含的项目多于包含:
构造函数的现有列表。
("key", "value") : existing
existing
是您已经制作的列表
您可以通过将状态从每个函数传递到下一个函数来跟踪函数之间的更改状态。这是State
monad所做的全部。 State s a
是a
类型的值,它取决于(并更改)状态s
。
{- ┌---- type of the state
v v-- type of the value -}
data State s a = State { runState :: s -> (a, s) }
{- ^ ^ ^ ^
a function ---|--┘ | |
that takes a state ---┘ | |
and returns | |
a value that depends on the state ---┘ |
and a new state ------┘ -}
>>=
的绑定操作State
取一个取决于(并改变)状态的值和一个函数来计算另一个取决于(并改变)状态的值并将它们组合起来制作一个取决于(并改变)状态的新值。
m >>= k = State $ \s ->
let ~(a, s') = runState m s
in runState (k a) s'