Haskell:为什么RealFrac并不表示分数? [英] Haskell: Why does RealFrac not imply Fractional?

查看:55
本文介绍了Haskell:为什么RealFrac并不表示分数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:此处提供了完整的源代码: https://gist.github.com/anonymous/7085509

NOTE: Full source code here: 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

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

Without a type signature, the compiler tells me the tournament signature is:

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

哪个对我很好.但是当我使用它时:

Which looks fine with me. But when I use it:

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实例.

Which leads to my first question, why doesn't RealFrac imply Fractional? The type signature has RealFrac, but the error complains about lack of an instance for Fractional.

第二,我将类型签名复制并粘贴回代码中,并添加 Fractional a :

Second, I copy-and-paste the type signature back into the code and add 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 .哪个引出了我的第二个问题:显然我误解了什么,但是呢?

Which now confuses me further because I don't have a type variable a0. Which leads to my second question: Obviously I'm misunderstanding something, but what?

推荐答案

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

In short, you need to fix a concrete type for 0.9 like Double. You can do that with an inline type annotation (0.9 :: Double).

很长一段时间:数字文字在Haskell中有点奇怪.通常,Haskell需要一种将语法( 0 0.0 0e0 )投影到语义( Int Integer Rational Double ),同时尽可能长地保持通用性( Num Fractional RealFrac ).让我们看看它是如何完成的.

In long: numeric literals are a little strange in Haskell. In general, Haskell needs a way to project syntax (0, 0.0, 0e0) into semantics (Int, Integer, Rational, Double) while maintaining generality for as long as possible (Num, Fractional, RealFrac). Let's see how it's done.

如果您自己键入数字文字,则会得到通用类型

If you type numeric literals by themselves you get generic types

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

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

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

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

Which means that we need to fix the concrete implementation of a before it can be used. In practice, this type variable a gets carried along

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

如果有帮助,可以认为将语法翻译为这样

If it's helpful, it can be useful to think of the syntax as being translated like this

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

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

But we can at various times eliminate the type variable

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

当我们从未声明过3时,Haskell如何知道3的类型?如果可能,它将默认.特别是,如果您打开 -Wall ,您会看到此

How does Haskell know what the type of 3 is when we've never declared it? It defaults, when possible. In particular, if you turn on -Wall you'll see this

>>> 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"

此默认行为由几乎从未使用过的编译指示 default 控制哪个默认"是

This defaulting behavior is controlled by an almost-never-used pragma default which "by default" is

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 .

So, what's likely happening is that you're constraining 0.9 to some class which Double does not instantiate. During its search, Haskell is giving up after not finding the Fractional class and it introduces that new a0 variable to represent this hitherto unreferenced, unknown type of 0.9.

首先,您可能希望对 Double 进行内联注释,以帮助推断者.可以将其添加到您的 default 列表中,但这是一个坏主意,因为人们很少使用该功能.

As stated at first, you probably want an inline annotation to Double to help the inferencer along. It's possible to add to your default list, but it's a bad idea as people rarely use that feature.

这篇关于Haskell:为什么RealFrac并不表示分数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆