我想创建一个配置字典,这样Haskell就可以像TOML一样使用。 为此,我创建了“字典”结构
Dictionary a
= Section [(String, Dictionary a)]
| Point a
key @ dictionary = Section [(key, dictionary)
key |= value = Section [(key, Point value)]
现在通过半群,我可以合并两个字典来创建一个新字典:
example_configuration =
"resolution" @ "width" |= 1920
<> "resolution" @ "height" |= 1080
但我认为总是必须通过半群运算符进行组合是有噪音的。
最初,我想为字典实现 Monad,这样我就可以使用 do 块。但单子自然需要允许改变旧的价值观。这是我不想要的。有没有办法为另一个运算符而不是绑定创建自定义块符号(就像这样做)? 也许是这样的:
example_configuration = combine
"resolution"@"width" |= 1920
"resolution"@"height" |= 1080
Writer
中,或者仅通过添加在数据结构中仅使用一次的类型参数来将其变成单子:
data Dictionary a r
= Section [(String, Dictionary a ())] r
| Point a r
instance Monad (Dictionary a) where
return = Section []
Section ls q >>= f = Section ls () <> f q --ish, some type matching is required
然后你就可以使用普通的
do
语法
example_configuration :: Dictionary Int ()
example_configuration = do
"resolution"@"width" |= 1920
"resolution"@"height" |= 1080
这是个好主意吗?有争议的。当然可以说,这只是滥用
do
语法来实现一些非常非单子的东西。另一方面,滥用这种语法实际上非常方便,特别是因为它通常允许省略括号。事实上,出于这个原因,我有时会在根本不是一元的值上使用
do
——只要do
块中只有一个语句,就不需要单子运算符,并且
do
只是充当括号,当缩进回落到之前的水平时,它会自动关闭。仍然被滥用,但非常有用。这样做的一个例子是HaTeX,例如我用 Haskell 来写我的整个博士论文。 对于
配置文件,我会同意chepner,即使用Haskell或另一种图灵完备的语言不是一个好主意,而是更好地使用像Dhall这样的专用语言。
do
表示法与
Monad
的元组实例一起使用。我认为
@
在 Haskell 中不是有效的标识符名称,因此在本例中我将其更改为
@.
。
key @. dictionary = (Section [(key, fst dictionary)], ())
key |= value = (Section [(key, Point value)], ())
exampleConfiguration = fst $ do
"resolution" @. "width" |= (1920 :: Integer)
"resolution" @. "height" |= (1080 :: Integer)