gpt4 book ai didi

Haskell:为什么 RealFrac 不暗示分数?

转载 作者:行者123 更新时间:2023-12-02 18:42:11 24 4
gpt4 key购买 nike

注意:完整源代码在这里:https://gist.github.com/anonymous/7085509

我有以下功能:

tournament n p pop = do
winner <- (\w -> min (n - 1) (floor (log w / log (1-p)))) <$> gaRandom
(flip S.index) winner <$> S.sort <$> seqChoose n pop

如果没有类型签名,编译器会告诉我锦标赛签名是:

tournament
:: (Floating a, Ord a1, RealFrac a, Random a) =>
Int -> a -> S.Seq a1 -> StateT GA Data.Functor.Identity.Identity a1

这对我来说看起来不错。但当我使用它时:

t2 = do
g <- newStdGen
let a = evalState (tournament 5 0.9 (S.fromList [1..10])) (GA g)
return ()

我收到错误:

GA.hs:85:37:
No instance for (Fractional a0) arising from the literal `0.9'
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Fractional Double -- Defined in `GHC.Float'
instance Fractional Float -- Defined in `GHC.Float'
instance Integral a => Fractional (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
...plus three others
In the second argument of `tournament', namely `0.9'
In the first argument of `evalState', namely
`(tournament 5 0.9 (S.fromList [1 .. 10]))'
In the expression:
evalState (tournament 5 0.9 (S.fromList [1 .. 10])) (GA g)

这引出了我的第一个问题,为什么RealFrac不暗示Fractional?类型签名具有 RealFrac,但错误提示缺少 Fractional 实例。

其次,我将类型签名复制并粘贴回代码中,并添加小数 a:

tournament 
:: (Floating a, Ord a1, RealFrac a, Fractional a, Random a) =>
Int -> a -> S.Seq a1 -> State GA a1
tournament n p pop = do
winner <- (\w -> min (n - 1) (floor (log w / log (1-p)))) <$> gaRandom
(flip S.index) winner <$> S.sort <$> seqChoose n pop

现在我得到的错误是:

GA.hs:88:24:
No instance for (Random a0) arising from a use of `tournament'
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
Note: there are several potential instances:
instance Random Bool -- Defined in `System.Random'
instance Random Foreign.C.Types.CChar -- Defined in `System.Random'
instance Random Foreign.C.Types.CDouble
-- Defined in `System.Random'
...plus 33 others
In the first argument of `evalState', namely
`(tournament 5 0.9 (S.fromList [1 .. 10]))'
In the expression:
evalState (tournament 5 0.9 (S.fromList [1 .. 10])) (GA g)
In an equation for `a':
a = evalState (tournament 5 0.9 (S.fromList [1 .. 10])) (GA g)

现在这让我更加困惑,因为我没有类型变量a0这引出了我的第二个问题:显然我误解了一些东西,但是什么?

最佳答案

简而言之,您需要为 0.9 修复具体类型,例如 Double。您可以使用内联类型注释 (0.9::Double) 来做到这一点。

总而言之:数字文字在 Haskell 中有点奇怪。一般来说,Haskell 需要一种将语法(00.00e0)投影为语义(IntIntegerRationalDouble),同时尽可能长时间地保持通用性(NumFractionalRealFrac)。让我们看看它是如何完成的。

如果您单独键入数字文字,您将获得泛型类型

>>> :t 1
1 :: Num a => a

>>> :t 1.0
1.0 :: Fractional a => a

>>> :t 1e0
1e0 :: Fractional a => a

这意味着我们需要先修复a的具体实现,然后才能使用它。实际上,这个类型变量a会被携带

>>> :t [1,2,3]
[1,2,3] :: Num a => [a]
>>> :t [1e0,2,3]
[1e0,2,3] :: Fractional a => [a]

如果有帮助,将语法视为这样翻译会很有用

1     ===   fromInteger  (1   :: Integer)   :: Num a        => a
1.0 === fromRational (1.0 :: Rational) :: Fractional a => a

但是我们可以在不同的时间消除类型变量

>>> :t show 3
show 3 :: String

当我们从未声明过 3 的类型时,Haskell 如何知道它是什么?如果可能的话,它会默认。特别是,如果你打开 -Wall 你会看到这个

>>> show 1e3

<interactive>:63:6: Warning:
Defaulting the following constraint(s) to type `Double'
(Fractional a0)
arising from the literal `1e3' at <interactive>:63:6-8
(Show a0) arising from a use of `show' at <interactive>:63:1-4
In the first argument of `show', namely `1e3'
In the expression: show 1e3
In an equation for `it': it = show 1e3

"1000.0"

此默认行为is controlled by an almost-never-used pragma default “默认情况下”是

default (Integer, Double)

其作用为

Each defaultable variable is replaced by the first type in the default list 
that is an instance of all the ambiguous variable's classes. It is a static
error if no such type is found.

因此,可能发生的情况是,您将 0.9 限制为 Double 未实例化的某个类。在搜索过程中,Haskell 在找不到 Fractional 类后放弃,并引入了新的 a0 变量来表示这种迄今为止未引用的未知类型的 0.9.

如一开始所述,您可能需要对 Double 进行内联注释来帮助推理器。可以添加到您的默认列表中,但这是一个坏主意,因为人们很少使用该功能。

关于Haskell:为什么 RealFrac 不暗示分数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19497940/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com