类型声明错误:[Char]和[[Char]]

时间:2012-02-08 23:27:26

标签: haskell

使用下面的代码片段,我想将一个字符串附加/前置一个列表,该列表是存储在地图中的值的一部分。

从下面的代码段我得到错误

Couldn't match expected type `Char' with actual type `[Char]'
    Expected type: Map.Map ([Char], Integer) [Char]
      Actual type: Map.Map ([Char], Integer) [[Char]]

我不太清楚应该告诉我什么。可以通过更改代码来解决,或者必须有类似

的内容
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleInstances #-}

与实例声明一起?

import Data.Time
import Data.Time.Clock.POSIX
import qualified Data.PSQueue as PSQ
import qualified Data.Map as Map
import Data.Maybe
import Control.Category
import Control.Concurrent
import Control.Concurrent.MVar
import Control.Monad

key = ("192.168.1.1", 4711)
messages = ["aaa", "bbbb", "ccccc"]

newRq = do
      time <- getPOSIXTime
      let q = PSQ.singleton key time
      let m = Map.singleton key messages
      return (q, m)

appendMsg :: String -> (String, Integer) -> Map.Map ([Char], Integer) [Char] -> Map.Map ([Char], Integer) [Char]
appendMsg  a (b, c) m = m2
      where 
          f x = x ++ a
          m2 = Map.adjust f (b, c) m

main :: IO()
main = do
     (q, m) <- newRq
     let m2 = appendMsg "first" key m
     print (m2)

3 个答案:

答案 0 :(得分:2)

您需要更改代码。您可以通过创建值为Map (String, Integer) [String]的单例来开始messages。但是,您的更新功能是为Map (String, Integer) String编写的。通过将其f x = x ++ [a](并将类型签名更改为

)将其更改为适当的类型
appendMsg :: String -> (String, Integer) -> Map (String, Integer) [String]
                                         -> Map (String, Integer) [String]

也可以使用例如更改您的初始地图unwords messages。 (我想你宁愿第一个。)

答案 1 :(得分:2)

[Char]和String是相同的类型。 Haskell前奏具有以下类型的同义词定义:

type String = [Char]

...这基本上意味着这两种类型意味着完全相同的东西,并且完全可以互换。这意味着我们可以将编译器错误重写为:

Expected type: Map (String, Integer) String
  Actual type: Map (String, Integer) [String]

Map类型的两个类型参数是其Key类型及其Value类型。因此,如果您使用Map Int String类型,则表示这是一张地图,其中Int为密钥,Strings为值。这意味着您现在可以更清楚地解释编译器消息:

Expected type: Map from keys of type "(String, Integer)" to values of type "String"
  Actual type: Map from keys of type "(String, Integer)" to values of type "[String]"

这告诉我们,在您的代码中的某个位置,您为其指定了一个地图,其中每个值都是[String](即字符串列表),但它期望一个地图中的每个值只是一个String。实际上,您可以将错误跟踪到这行代码:

let m = Map.singleton key messages

messages,您猜对了,String s列表(即[String]),您告诉它将整个数组messages存储为单个元素在使用m函数初始化它时,在地图singleton中。所以Haskell正确地推断出m的值类型必须是[String](这显然不是你想要的)。

当您尝试将字符串附加到地图中以下行中的每个元素时,编译器会注意到有些不对劲:

let m2 = appendMsg "first" key m

你告诉编译器“请将这个字符串连接到我的地图的每个元素上”然后编译器会告诉你“但你没有在你的地图中存储多个字符串;你只有一个字符串列表存储为一个你的地图中的值,所以我不能将'first'追加到数组本身“。

修复很简单,而不是使用singleton初始化m,而只需fromList,它会获取元素列表(即messages)并转换每个元素在列表中的一个元素,这是你想要的。

答案 2 :(得分:1)

您使用Map.singleton key messages创建的地图是Map.Map (String, Integer) [String]。但是,您appendMsg的声明表明您确实需要Map.Map (String, Integer) String。您需要重新访问newRq并找出您真正尝试使用Map.singleton行的内容。