Haskell类型匹配错误

时间:2017-04-05 14:07:10

标签: haskell

我已经定义了几个类型的同义词,如下所示:

type Potential = Float
type Label = String
type LabelSet = [String]

此外,我已定义以下类型并键入同义词:

data VariableNode = VariableNode Label Potential LabelSet
type PGM = [VariableNode]

最后,以下函数构造一个图形:

makePGM :: [((Label, Potential), LabelSet)] -> PGM
makePGM (x:xs) = (VariableNode (fst . fst x) (snd . fst x) (snd x)) : makePGM xs
makePGM [] = []

在上面的函数中,根据函数类型签名,提供元组列表,其中元组的第一个元素是另一个元组,第二个元素是列表。

我是Haskell的新手,因此在解密以下错误消息时遇到一些困难:

Prelude> :l Graph.hs
[1 of 1] Compiling Graph            ( Graph.hs, interpreted )

Graph.hs:14:33: error:
    • Couldn't match type ‘a0 -> c0’ with ‘[Char]’
      Expected type: Label
        Actual type: a0 -> c0
    • Probable cause: ‘(.)’ is applied to too few arguments
      In the first argument of ‘VariableNode’, namely ‘(fst . fst x)’
      In the first argument of ‘(:)’, namely
        ‘(VariableNode (fst . fst x) (snd . fst x) (snd x))’
      In the expression:
        (VariableNode (fst . fst x) (snd . fst x) (snd x)) : makePGM xs

Graph.hs:14:39: error:
    • Couldn't match expected type ‘a0 -> (c0, b0)’
                  with actual type ‘(Label, Potential)’
    • Possible cause: ‘fst’ is applied to too many arguments
      In the second argument of ‘(.)’, namely ‘fst x’
      In the first argument of ‘VariableNode’, namely ‘(fst . fst x)’
      In the first argument of ‘(:)’, namely
        ‘(VariableNode (fst . fst x) (snd . fst x) (snd x))’

Graph.hs:14:47: error:
    • Couldn't match type ‘a1 -> c1’ with ‘Float’
      Expected type: Potential
        Actual type: a1 -> c1
    • Probable cause: ‘(.)’ is applied to too few arguments
      In the second argument of ‘VariableNode’, namely ‘(snd . fst x)’
      In the first argument of ‘(:)’, namely
        ‘(VariableNode (fst . fst x) (snd . fst x) (snd x))’
      In the expression:
        (VariableNode (fst . fst x) (snd . fst x) (snd x)) : makePGM xs

Graph.hs:14:53: error:
    • Couldn't match expected type ‘a1 -> (a2, c1)’
                  with actual type ‘(Label, Potential)’
    • Possible cause: ‘fst’ is applied to too many arguments
      In the second argument of ‘(.)’, namely ‘fst x’
      In the second argument of ‘VariableNode’, namely ‘(snd . fst x)’
      In the first argument of ‘(:)’, namely
        ‘(VariableNode (fst . fst x) (snd . fst x) (snd x))’
Failed, modules loaded: none.

我已经得出结论认为存在类型不匹配但不清楚如何定义我给定的类型和函数类型签名。

2 个答案:

答案 0 :(得分:2)

问题是f . g xf . (g x)。因此,类型不匹配:

fst . fst ((1,2),3)
  == fst . (fst ((1,2),3))
  == fst . (1,2)
  == ???? (.) expects a function, not a value

您必须在fst . fst$附近使用括号:

-- reminder:
(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g x = f (g x)

($) :: (a -> b) -> a -> b
($) f x = f x 

(fst . fst) x
 == fst (fst  x)

fst $ fst x
 == fst (fst x)

你也可以将两者结合起来,例如: fst . fst $ x,因为$的优先级很低。

答案 1 :(得分:0)

当然,这是一个很有用的练习,由于犯了这个错误,你已经学会了更好地理解Haskell中的运算符优先级和解析。但是,一旦你有了更多的经验,你就会意识到你可以避免这个问题,并因此使用简单的代码,通过使用模式匹配而不是组合对fstsnd的调用: / p>

makePGM :: [((Label, Potential), LabelSet)] -> PGM
makePGM (((label, potential), set):xs) = VariableNode label potential set : makePGM xs
makePGM [] = []

现在代码的形状与它所消耗的数据相似,您可以为使用的值提供描述性名称。

另一个改进来自于观察到这种递归模式非常常见:您对列表中的每个项执行某些操作,彼此独立,并构造结果列表。事实上,这正是map的作用。因此,您可以编写一个函数,一次只处理其中一个PGM项,然后使用map将其扩展为适用于它们列表的函数:

makePGM :: [((Label, Potential), LabelSet)] -> PGM
makePGM = map go
  where go ((label, potential), set) = VariableNode label potential set