Haskell:为什么RealFrac并不意味着分数?

时间:2013-10-21 14:58:29

标签: haskell types

注意:完整的源代码在此处: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签名是:

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的实例。

其次,我将类型签名复制并粘贴回代码并添加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这引出了我的第二个问题:显然我误解了什么,但是什么?

2 个答案:

答案 0 :(得分:7)

简而言之,您需要为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

当我们从未声明它时,Haskell如何知道3的类型是什么?如果可能,它默认为。特别是,如果您打开-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的内联注释来帮助推理器。可以添加到您的default列表中,但这是一个坏主意,因为人们很少使用该功能。

答案 1 :(得分:2)

问题不在于类型类,而是GHC不知道哪个实例用于`(小数a,RealFrac a,浮动a,随机a)。如果您将其指定为

tournament 5 (0.9 :: Double) (S.fromList [1..10])

然后它应该工作(或者至少它使用你的要点为我工作)