如何从函数返回Data.Map

dem*_*mas 6 haskell

这个功能有效:

serialExpansion num = Map.fromList (zip (listOfSimpleDividers num) (powers num))
Run Code Online (Sandbox Code Playgroud)

但是当我搭便车:

serialExpansion :: Int -> Map
serialExpansion num = Map.fromList (zip (listOfSimpleDividers num) (powers num))
Run Code Online (Sandbox Code Playgroud)

我收到错误:

simplifier.hs:46:26: Not in scope: type constructor or class `Map'
Run Code Online (Sandbox Code Playgroud)

我该如何申报这个功能?

gsp*_*spr 12

Map是参数化数据类型(也称为抽象数据类型).只有在为键指定类型和值的类型时,才能获得完全定义的类型.

例如,允许您String通过Integers 查找的地图具有类型Map Integer String.

此外,您似乎已导入Map限定(如您所愿).因此,您必须使用Map.Map而不是仅Map在签名中使用.

因此,你的功能应该有一个签名

 serialExpansion :: Int -> Map.Map Key Value
Run Code Online (Sandbox Code Playgroud)

Key密钥数据类型在哪里,Value是值数据类型.在你的情况下,如果我猜,也许你想要Int两者KeyValue.确切地说:您希望Key与列表中元素的类型相同listOfSimpleDividers num,并且Value与列表中元素的类型相同powers num.(Map.fromList如果不清楚,可能有助于检查类型签名).

到现在为止你可能会问:"但是如果你能告诉正确的返回类型serialExpansion,为什么编译器不能?" 它可以.这正是你的第一个例子工作的原因.由于您省略了类型签名,因此编译器会从上下文中推断出它.正如您刚刚所经历的那样,编写类型签名可以是确保您完全理解代码(而不是依赖于类型推断)的好方法.

  • 参数化数据类型(也称为抽象数据类型) - "参数化"和"抽象"是不一样的.它们是独立的概念 - 数据类型可以是其中之一或两者. (2认同)

Tra*_*own 8

两点补充gspr的答案:

导入Map非限定类型构造函数然后导入合格模块的其余部分是一种常见做法:

import Data.Map (Map)
import qualified Data.Map as Map
Run Code Online (Sandbox Code Playgroud)

这样可以避免Map.Map在任何地方写入类型签名.

此外,在GHCi或Hugs中,您可以使用:t向交互式环境询问任何函数的推断类型.例如,如果我在GHCi中加载此文件:

import Data.Map (Map)
import qualified Data.Map as Map

serialExpansion num = Map.fromList (zip (listOfSimpleDividers num) (powers num))
  where
    powers = undefined
    listOfSimpleDividers = undefined
Run Code Online (Sandbox Code Playgroud)

我得到以下内容:

*Main> :t serialExpansion
serialExpansion :: (Ord k) => t -> Map k a
Run Code Online (Sandbox Code Playgroud)

如果你在自己的定义插件powerslistOfSimpleDividers你会得到一个更具体的类型.