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

Dan*_*Dan 5 lambda haskell types

我想打号码列表中的每个0.1-150150.

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

let indices = [-1500,-1499..1500]
let grid = map (\x -> 0.1 *x) indices
Run Code Online (Sandbox Code Playgroud)

这使得ghci吐出错误.

另一方面,这两个都很好:

let a = 0.1*2
Run Code Online (Sandbox Code Playgroud)

let grid = map (\x -> 2 *x) indices
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?为什么当应用于带有地图的列表时,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)'
Run Code Online (Sandbox Code Playgroud)

kpu*_*nam 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的更多信息.


drq*_*ver 8

这是违约.

你的indices变量,而不是Num你所期望的类型类的多态,是默认为Integer,此时你不能将它乘以0.1,因为0.1它将解析为某些Fractional类型.

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

let indices :: (Enum a, Num a) => [a]; indices = [-1500,-1499..1500]
Run Code Online (Sandbox Code Playgroud)

虽然在实践中你并不经常想要以这种方式显式的多态列表.

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

  • 请注意,如果您将这些定义放在一个文件中,那么即使没有类型签名,一切都很好.单态限制仍然适用,但在整个上下文可用GHC可以选择*正确*单态类型而不是"[整数]".默认工作的方式不是那么愚蠢,只是一次一个地绑定到ghci会迫使GHC"盲目工作". (3认同)