如何为此函数编写类型声明?

2 haskell types declaration division

我仍然是Haskell的新手,我遇到了一个问题,可能不应该太难解决,但完全让我难过.

我写了一个函数:

maxFor l n = n * m * (m + 1) / 2 where m = l `div` n
Run Code Online (Sandbox Code Playgroud)

该函数属于一个小模块,加载没有问题,但每当我尝试在加载模块后使用该函数时,会抛出两个令人尴尬的神秘错误:

<interactive>:182:1:
    No instance for (Integral a0) arising from a use of `maxFor'
    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 Integral Int -- Defined in `GHC.Real'
      instance Integral Integer -- Defined in `GHC.Real'
      instance Integral GHC.Types.Word -- Defined in `GHC.Real'
    In the expression: maxFor 999 5
    In an equation for `it': it = maxFor 999 5

<interactive>:182:8:
    No instance for (Num a0) arising from the literal `999'
    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 Num Double -- Defined in `GHC.Float'
      instance Num Float -- Defined in `GHC.Float'
      instance Integral a => Num (GHC.Real.Ratio a)
        -- Defined in `GHC.Real'
      ...plus three others
    In the first argument of `maxFor', namely `999'
    In the expression: maxFor 999 5
    In an equation for `it': it = maxFor 999 5
Run Code Online (Sandbox Code Playgroud)

我理解它告诉我我的函数缺少一个正确的类型声明,但我不明白如何编写它没有编译器再次唠叨.我尝试了无数变种,我不明白实际问题并没有帮助我解决问题.

部分问题可能是我正在使用(/)div在一个函数中,因此所需的类型声明可能包含Fractional和/或Integral,因为:

(/) :: Fractional a => a -> a -> a
Run Code Online (Sandbox Code Playgroud)

和:

div :: Integral a => a -> a -> a
Run Code Online (Sandbox Code Playgroud)

但就我而言,我已经陷入困境.我该如何编写类型声明maxFor?我究竟做错了什么?我是否遗漏或忽略了一些显而易见的事情?

非常感谢任何帮助和建设性的反馈.

编辑:我已经在堆栈溢出上找到了这个答案,这已经有所帮助了.我仍然很感激帮助,但我当然会删除这个问题,如果事实证明我是一个白痴并最终被投票.

Zet*_*eta 5

注意:这篇文章是用文字Haskell编写的.您可以将其保存为Max.lhs并在GHCi中尝试.


快速解决方案

首先,让我们推断你的使用(/2).这个数字是n * m * (m + 1)奇数还是偶数?好吧,要么m是奇怪的,要么是m + 1均匀的,因此整个产品是均匀的,或者m甚至是相同的论点.

因此n * m * (m + 1) / 2,我们可以使用n * m * (m + 1) `div` 2:

> maxFor l n = n * m * (m + 1) `div` 2 
>    where m = l `div` n
Run Code Online (Sandbox Code Playgroud)

现在,我们所要做的就是检查我们使用的函数的类型:

(+)  :: Num a => a -> a -> a
(*)  :: Num a => a -> a -> a
div  :: Integral n => n -> n -> n
Run Code Online (Sandbox Code Playgroud)

这直接导致您的类型:

> maxFor :: Integral n => n -> n -> n
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用某种特定类型来解决错误:

maxFor :: Integer -> Integer -> Integer
-- Now GHC yells at you since Integer doesn't have a Fractional instance
-- and you try to use (/).
Run Code Online (Sandbox Code Playgroud)

背景资料

你已经认识到了这个问题.div表示l并且n是一些整数类型,但(/)表示它们是小数的.在通常情况下Prelude,没有数据类型是两个类型类的实例.你可以在GHCi中查看:

Prelude> :info Fractional
class Num a => Fractional a where
  (/) :: a -> a -> a
  recip :: a -> a
  fromRational :: Rational -> a
    -- Defined in ‘GHC.Real’

instance Fractional Float -- Defined in ‘GHC.Float’
instance Fractional Double -- Defined in ‘GHC.Float’

Prelude> :info Integral
class (Real a, Enum a) => Integral a where
  quot :: a -> a -> a
  rem :: a -> a -> a
  div :: a -> a -> a
  mod :: a -> a -> a
  quotRem :: a -> a -> (a, a)
  divMod :: a -> a -> (a, a)
  toInteger :: a -> Integer
    -- Defined in ‘GHC.Real’
instance Integral Word -- Defined in ‘GHC.Real’
instance Integral Integer -- Defined in ‘GHC.Real’
instance Integral Int -- Defined in ‘GHC.Real’
Run Code Online (Sandbox Code Playgroud)

这是第一部分.

第二部分源于文字.999或者5有类型Num a => a.现在GHC是一个进退两难的境地:它必须找到一个Num实例,这是两个IntegralFractional.由于没有这种类型(见上文),GHC因模棱两可而放弃.您也可以在GHCi中查看:

Prelude> 5 :: Num a => a
5

Prelude> 5 :: (Fractional a, Integral a) => a
<interactive>:7:1:
    No instance for (Fractional a0) arising from a use of ‘it’
    The type variable ‘a0’ is ambiguous
    Note: there are several potential instances:
      instance Integral a => Fractional (GHC.Real.Ratio a)
        -- Defined in ‘GHC.Real’
      instance Fractional Double -- Defined in ‘GHC.Float’
      instance Fractional Float -- Defined in ‘GHC.Float’
    In the first argument of ‘print’, namely ‘it’
    In a stmt of an interactive GHCi command: print it
Run Code Online (Sandbox Code Playgroud)

所以这主要是你最终得出错误的原因.

  • 每当`m`为奇数时,@ idumediae`m*(m + 1)`也是偶数,因为`m + 1`将是偶数. (2认同)