为什么我不能将一个乘以Fractional的函数映射到Nums列表中?

时间:2013-04-04 05:45:01

标签: haskell types lambda

我想从0.1-150每隔150制作一个数字列表。

为此,我创建了一个列表,然后尝试将Fractional multiplication lambda映射到它上面,如下所示:

let indices = [-1500,-1499..1500]
let grid = map (\x -> 0.1 *x) indices

这使得ghci吐出错误。

另一方面,这两项工作都很好:

let a = 0.1*2

let grid = map (\x -> 2 *x) indices

这里发生了什么?为什么当应用于带有map的列表时,Num乘以Fractional的乘法才会失败?

编辑: 我得到的错误是:

No instance for (Fractional Integer)
  arising from the literal `0.1'
Possible fix: add an instance declaration for (Fractional Integer)
In the first argument of `(*)', namely `0.1'
In the expression: 0.1 * x
In the first argument of `map', namely `(\ x -> 0.1 * x)'

4 个答案:

答案 0 :(得分:10)

你发现了“可怕的单态限制”。基本上,GHC会将indices的类型推断为类似[Integer]而不是Num a => a的类型。您可以提供indices :: [Float]之类的注释,也可以修改定义以避免限制。

例如(不是建议),如果您使indices成为函数let indices a = [-1500, -1499..1500],则推断类型现为(Enum t, Num t) => a -> [t]a参数未使用但违反了限制。然后,您可以map f (indices whatever)。请参阅Haskell Wiki中有关Monomorphism Restriction

的更多信息

答案 1 :(得分:8)

这是违约。

您的indices变量,而不是您所期望的Num类型类的多态,是默认为Integer,此时您无法将其乘以0.1,因为0.1将解析为某种Fractional类型。

您可以使用显式类型签名强制索引具有多态性:

let indices :: (Enum a, Num a) => [a]; indices = [-1500,-1499..1500]

虽然在实践中你并不经常想要那样明确的多态列表。

有一个关于haskell wiki上的单态限制的页面,虽然它不是特别简洁:http://www.haskell.org/haskellwiki/Monomorphism_restriction

答案 2 :(得分:1)

let grid = map (\x -> 0.1 * (fromInteger x)) indices

- 网格[-150.0,-149.9,-149.8,-149.70000000000002,-149.6,-149.5 ......]

答案 3 :(得分:-1)

以下代码为我工作

let indices = [-1500,-1499..1500]

let grid = map ( \x -> x /10 ) indices

它不喜欢0.1

有关完整说明,请参阅此link

上的“单形故障”部分