0

我目前正在尝试创建一个(某种)类型安全的 xml,例如嵌入到 Haskell 中的语法。最后,我希望实现这样的目标:

tree = group [arg1 "str", arg2 42] 
         [item [foo, bar] []
         ,item [foo, bar] []
         ]

其中 group 和 item 是 kind Node :: [Arg t] -> [Node c] -> Node t。如果这没有任何意义,那很可能是因为我不知道自己在做什么:)

我现在的问题是如何使类型系统阻止我向Node. 例如Nodes 类型Grouponly 可能有类型参数,Arg1Arg2sItem可能有类型参数FooBar

我想底线问题是:我如何限制异构列表中的类型?


我试图实现的(用户)语法示例:

group .: arg1 "str" .: arg2 42
    item .: foo .: bar
    item .: foo .: bar

其中 (.:) 是在节点中设置参数的函数。这将表示具有一些包含两个项目的参数的组。

此外,还会有一些(伪)定义,例如:

data Node = Node PossibleArguments PossibleChildNodes

type Group = Node [Arg1, Arg2] [Item]
type Item  = Node [Foo, Bar] []

我正在寻找一种通过类型检查器捕获使用错误的方法。

4

2 回答 2

3

你所拥有的对我来说听起来不像你需要一个异构的列表。也许你正在寻找这样的东西?

data Foo = Foo Int

data Bar = Bar Int

data Arg = StringArg String | IntArg Int | DoubleArg Double

data Tree = Group Arg Arg [Item]

data Item = Item Foo Bar

example :: Tree
example = Group (StringArg "str") (IntArg 42)
            [Item (Foo 1) (Bar 2), Item (Foo 12) (Bar 36)]

请注意,我们甚至可以创建一个Arg不同“子类型”的列表。例如,[StringArg "hello", IntArg 3, DoubleArg 12.0]。不过,它仍然是一个同类列表。

===== 编辑 =====

有几种方法可以处理“默认参数”的情况。假设Bar项目中的参数是可选的。我的第一个想法是,虽然用户指定它可能是可选的,但当我存储数据时,我想包含默认参数。这样,确定默认值与实际使用它的代码是分开的。因此,如果用户指定 aFoo为 3,但未提供 a Bar,并且默认值为Bar 77,那么我将我的项目创建为:

Item (Foo 3) (Bar 77)

这样做的好处是对这个对象进行操作的函数不需要担心默认值;就它们而言,这两个参数将始终存在。

然而,如果你真的想在你的数据结构中省略默认参数,你可以这样做:

data Bar = Bar Int | DefaultBar

example = Group (StringArg "str") (IntArg 42)
            [Item (Foo 1) (Bar 2), Item (Foo 12) DefaultBar]

甚至:

data Item = Item Foo Bar | ItemWithDefaultBar Foo

===== 编辑#2 =====

所以也许你可以使用这样的东西:

data ComplicatedItem = ComplicatedItem 
    {
      location :: (Double, Double),
      size :: Int,
      rotation :: Double,
      . . . and so on . . .
    }

defaultComplicatedItem = ComplicatedItem { location = (0.0,0.0), size = 1, rotation = 0.0), ... }

要创建ComplicatedItem,用户只需指定非默认参数:

myComplicatedItem = defaultComplicatedItem { size=3 }

如果向ComplicatedItem类型添加新参数,则需要更新defaultComplicatedItem,但 for 的定义myComplicatedItem不会改变。

您还可以覆盖该show函数,以便在打印时省略默认参数。

于 2013-01-15T13:55:22.283 回答
1

根据随后的讨论,听起来您想要的是创建一种 DSL(域特定语言)来表示 XML。

一种选择是将你的 DSL嵌入到 Haskell 中,这样它就可以出现在 Haskell 源代码中。通常,您可以通过定义所需的类型并提供一组函数来处理这些类型来做到这一点。听起来这就是你希望做的。但是,作为嵌入式DSL,它会受到一些限制,这就是您遇到的问题。也许有一个聪明的技巧可以做你想做的事情,也许是涉及类型函数的事情,但我目前想不出任何东西。如果您想继续尝试,可以添加标签dslgadt在您的问题中,引起比我更了解这些东西的人的注意。或者,您可以使用类似 Template Haskell或者废弃你的样板文件,让你的用户省略一些信息,这些信息会在 Haskell “看到”它之前被“填充”。

另一种选择是拥有一个外部 DSL,您可以使用 Haskell 对其进行解析。您可以定义 DSL,但直接使用 XML 和合适的 DTD 可能会更容易。当然,有用于解析 XML 的 Haskell 库。

于 2013-01-17T13:04:15.003 回答