Map.insert无故提示Haskell错误

Map.insert prompting an error in Haskell without reason

这是我正在使用的功能:

threeWordFunction :: [String] -> Map.Map String [String] -> String
threeWordFunction [x, y, z] orbitingData = do
     Map.insert z [x, y] orbitingData
     ""

导致以下错误:

src\MyLib.hs:40:6: error:
    * Couldn't match type `Map.Map String' with `[]'
      Expected type: [[String]]
        Actual type: Map.Map String [String]
    * In a stmt of a 'do' block: Map.insert z [x, y] orbitingData
      In the expression:
        do Map.insert z [x, y] orbitingData
           ""
      In an equation for `threeWordFunction':
          threeWordFunction [x, y, z] orbitingData
            = do Map.insert z [x, ....] orbitingData
                 ""
   |
40 |      Map.insert z [x, y] orbitingData
   |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

我尝试了一大堆修复方法,但没有发现任何可能导致此错误的方法。该函数只是试图将字符串添加到地图中,没什么特别的。任何帮助将不胜感激。

问题

正如一些贡献者所说,do 是问题所在。 但是,让我尝试分解你想要的(如我所见)和你所做的。

threeWordFunction :: [String] -> Map.Map String [String] -> String

声明函数的类型。这是你打算做的。对于 StringMap 的列表,您想提供 String。如果我在 Haskell 中读到这篇文章,我会推断您可能想使用 Map 来提取一些有用的东西来构建 String。实际上,您的函数的唯一输出是 String。由于 Map 不是输出,任何修改都将“丢失”。

当我读到你想做什么时,你声称你想在 Map 中插入一个值。所以我想你想输出结果 Map。在这里我可以推断出你的第一个错误:你认为有副作用。我假设您想在函数内部修改 Map,并且您期望 Map 将在函数外部进行修改。但这不是 Haskell 的工作方式。这就是大多数具有命令式特性的语言的工作方式。

所以要这个你要用do这个词。这背后的想法是提供一系列指令,例如 C-block 中带有花括号的指令。这是错误的。在 Haskell 中,do 词是语法糖,它指出了你在一个 monad 中的事实......所以你的计算结果可能是一个 monad。但这不是函数类型所说的。所以编译器会产生错误。

怎么做才能和你的类型保持一致

考虑到类型,Chi提供的解决方案。

threeWordFunction [x, y, z] orbitingData = let newMap = Map.insert z [x, y] orbitingData in ""

编译器不会再报错了。您构建了一个新地图 newMap,它可以按照您想要的方式进行修改。您提供 String "" 作为输出。但是, newMap 将永远无法在您的函数之外访问。所以插入没用。

你可以做什么来满足你的需求

更改类型...Haskell 中的类型提供了明确定义预期有效解决方案(或多或少)的规范。

因此您可能需要明确提供地图的东西。

threeWordFunction :: [String] -> Map.Map String [String] -> Map.Map String [String]

或一个映射和一个字符串

threeWordFunction :: [String] -> Map.Map String [String] -> (Map.Map String [String], String)

您也可以像 State 一样使用 monad,但对于您的水平来说它可能太多了。

考虑到新类型,您现在可以 return 一个您需要的实体。

threeWordFunction :: [String] -> Map.Map String [String] -> (Map.Map String [String], String)
threeWordFunction [x, y, z] orbitingData = 
    let newMap = Map.insert z [x, y] orbitingData 
    in (newMap, "") 

注意,如果您总是想提供一个 "" 作为字符串,这可能表明您不需要它。

希望这能帮助您理解问题。