在 haskell 中增加列表
Growing a list in haskell
我正在学习 Haskell 通过编写 OSC 音乐音序器将其与 SuperCollider 一起使用。但是因为我想用它制作相当复杂的东西,所以它会像编程语言一样工作,您可以在其中声明变量和定义函数,这样您就可以以算法的方式编写音乐。语法是不寻常的,因为我们正在编码序列,有时一个小节会引用最后一个小节(类似于 "play that last chord again but a fifth above")。
我对自己的解释不满意,但这是我能做到的最好的解释。
无论如何,我现在正在编码的是该语言的解析器,到目前为止是无状态的,但现在我需要一些方法来使用 [("key","value")]
时尚,所以我可以在逐条解析时添加新值。
我知道这涉及 monads,我还不是很了解,但我需要一些足够有意义的东西来开始玩弄它们,否则我会发现原始理论有点太原始了。
那么什么是干净简单的开始方式呢?
如果问题太长,谢谢,抱歉。
编辑它的工作原理:
我们输入一个字符串给主要的解析函数,比如说
"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.
等等
但有时它会变得比这更复杂,不要让我解释为什么我会让你无聊死。
将项目添加到列表
您可以使用 :
构造函数创建一个包含比现有列表多一项的新列表。
("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'
我正在学习 Haskell 通过编写 OSC 音乐音序器将其与 SuperCollider 一起使用。但是因为我想用它制作相当复杂的东西,所以它会像编程语言一样工作,您可以在其中声明变量和定义函数,这样您就可以以算法的方式编写音乐。语法是不寻常的,因为我们正在编码序列,有时一个小节会引用最后一个小节(类似于 "play that last chord again but a fifth above")。 我对自己的解释不满意,但这是我能做到的最好的解释。
无论如何,我现在正在编码的是该语言的解析器,到目前为止是无状态的,但现在我需要一些方法来使用 [("key","value")]
时尚,所以我可以在逐条解析时添加新值。
我知道这涉及 monads,我还不是很了解,但我需要一些足够有意义的东西来开始玩弄它们,否则我会发现原始理论有点太原始了。
那么什么是干净简单的开始方式呢? 如果问题太长,谢谢,抱歉。
编辑它的工作原理:
我们输入一个字符串给主要的解析函数,比如说
"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.
等等
但有时它会变得比这更复杂,不要让我解释为什么我会让你无聊死。
将项目添加到列表
您可以使用 :
构造函数创建一个包含比现有列表多一项的新列表。
("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'