我想创建一个配置字典,这样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

8

  • IIRC,do-blocks 也适用于 Applicative…但我不确定这对您有帮助。


    – 

  • 3
    我建议不要使用 Haskell 作为配置语言。如果您想要为配置文件设计并保留 Haskell 的许多精髓的东西,我会推荐


    – 

  • (Dhall 是强静态类型,更重要的是,它不是Turning-complete,因此您可以定义函数来减少样板文件,而不必担心无限循环。)


    – 

  • 3
    列表表示法本质上每行只需要一个逗号。我会用那个。 (此外,您的类型参数a未使用 – 您真的需要它吗?)


    – 

  • 也许可以do为此“(ab)使用”符号,但这通常是通过列表而不是do符号来完成的。


    – 


2 个回答
2

您可以通过将任何幺半群包装在 中,或者仅添加在数据结构中只使用一次的类型参数,将其转换为单子:

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不是单子的值– 只要块中只有一个语句,就不需要单子运算符,并且只需充当括号,在缩进时自动关闭回落到之前的水平。仍然被滥用,但非常有用。这样做的一个例子是,例如我用它来用 Haskell 写我的整个博士论文。dodo

然而,对于配置文件,我观点,即使用 Haskell 或另一种图灵完备的语言不是一个好主意,而是更好地使用像这样的专用语言。

您可以do对 的元组实例使用表示法Monad

key @ dictionary = (Section [(key, fst dictionary)], ())
key |= value = (Section [(key, Point value)], ())

exampleConfiguration = fst $ do
  "resolution" @ "width" |= 1920
  "resolution" @ "height" |= 1080

2

  • 2
    偏离主题,但实际上@只要您小心处理空格,作为运算符就可以很好地工作。我相信TypeApplications,打开扩展后,x@y是一种模式,x @y是一种类型应用程序,并且x @ y是在操作员调用中。


    – 

  • @KABuhr 已修复,谢谢!我在本地测试中确实对空格不够小心。


    –