这个功能有效:
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两者Key和Value.确切地说:您希望Key与列表中元素的类型相同listOfSimpleDividers num,并且Value与列表中元素的类型相同powers num.(Map.fromList如果不清楚,可能有助于检查类型签名).
到现在为止你可能会问:"但是如果你能告诉正确的返回类型serialExpansion,为什么编译器不能?" 它可以.这正是你的第一个例子工作的原因.由于您省略了类型签名,因此编译器会从上下文中推断出它.正如您刚刚所经历的那样,编写类型签名可以是确保您完全理解代码(而不是依赖于类型推断)的好方法.
两点补充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)
如果你在自己的定义插件powers和listOfSimpleDividers你会得到一个更具体的类型.