无法匹配预期类型'Term'

时间:2017-11-08 16:51:17

标签: haskell

我正在尝试开发一个match函数,将两个Tuplas组合成一个Record,它具有以下组合[(Label,Value)]。第一个元组,必须只有String类型的元素,第二个元组可以是任何其他类型的元素。

代码是:

type RItem = (Label, Term)

type TItem = (Term)

type Label = String

data Term = Record [RItem]
          | Tuple [TItem]
          | B Bool
          | N Int
          | S String
        deriving(Eq, Show)  

match :: Term -> Term -> Term
match (Tuple _) (Tuple []) = Record []
match (Tuple []) (Tuple _) = Record []
match (Tuple (x:xs)) (Tuple (z:zs)) = [(x,z)] ++ match (Tuple xs) (Tuple zs)

但是,在编译上面的代码时,会显示以下错误:

enter image description here

应该在此程序中编写和使用的代码示例如下:

> t1 = Tuple [(S "a"), (S "b")]
> t2 = Tuple [(N 10), (N 20)]
> match t1 t2

有效结果应为Record :: Record [("a", 10), ("b", 20)]

2 个答案:

答案 0 :(得分:1)

xTerm但是为了返回您想要的类型,您需要它是Label。所以你需要在标签上进行模式匹配。

match (Tuple (S x : xs)) (Tuple (z : zs)) = [(x, z)] ++ match (Tuple xs) (Tuple zs)

但这提出了一个问题:如果我通过match (Tuple [B True]) (Tuple [N 10])该怎么办?根据您的类型,我们不能为键定义带有布尔值的Record。该程序应该崩溃吗?或者我们应该得到一些“默认”行为?您可以考虑更改匹配,以便将[Label]作为其第一个参数,而不是通用Term。这样就无需进行所有这种模式匹配,因此它更加清晰,并且阻止人们将无意义的数据传递给它,因此它更加正确。

如果出于某种原因,您需要人员能够将普通Term传递给match,您可以考虑返回Maybe,以便您可以优雅地处理失败案例。

答案 1 :(得分:1)

问题在于

match (Tuple (x:xs)) (Tuple (z:zs)) = [(x,z)] ++ match (Tuple xs) (Tuple zs)

递归调用的结果将是Term,因此您无法将列表并置运算符++应用于它。此外,这种连接的结果将是一个列表,而不是Term,因此您最终会得到错误的结果类型。

这里的基础操作实际上只是标准

zip :: [a] -> [b] -> [(a,b)]

所以让我们建立在那个:

match (Tuple labels) (Tuple terms) = Record (zip labels terms)

正如其他人所说,这有点奇怪,因为它会因非Tuple值而失败。所以你可能想要更像

的东西
match2 :: [Label] -> [Term] -> Term
match2 labels values = Record (zip labels values)

但这仍然令人惊讶,因为从不同长度的标签和值列表构建记录似乎没什么意义。也许你可以使用

match3 :: [Label] -> [Term] -> Maybe Term
match3 ls ts = Record <$> zipSame ls ts

zipSame :: [a] -> [b] -> Maybe [(a,b)]
zipSame [] [] = Just []
zipSame (l:ls) (t:ts) = ((l,t):) <$> zipSame ls ts
zipSame _ _ = Nothing
相关问题