如何为此函数编写类型声明?
How do I write a type declaration for this function?
我对 Haskell 还是个新手,我遇到了一个问题,这个问题应该不难解决,但完全难倒了我。
我写了一个函数:
maxFor l n = n * m * (m + 1) / 2 where m = l `div` n
该函数属于一个加载没有问题的小模块,但每当我在加载该模块后尝试使用该函数时,就会抛出两个对我来说令人尴尬的神秘错误:
<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
我知道它告诉我我的函数缺少正确的类型声明,但我不明白如何在编译器不再唠叨的情况下编写它。我已经尝试了无数种变体,但我不了解实际问题并不能帮助我解决问题。
部分问题可能是我在一个函数中使用了 (/)
和 div
,因此所需的类型声明可能包含 Fractional
and/or Integral
, 因为:
(/) :: Fractional a => a -> a -> a
和:
div :: Integral a => a -> a -> a
但这就是我所知道的,我被卡住了。我将如何编写 maxFor
的类型声明?我究竟做错了什么?我是否遗漏或忽略了一些显而易见的事情?
非常感谢任何帮助和建设性反馈。
编辑:我找到了关于堆栈溢出的 this 答案,这已经有点帮助了。我仍然很感激帮助,但我当然会删除这个问题,如果事实证明我是个白痴并最终被否决。
注:这个post是写在literate Haskell里的。您可以将其保存为 Max.lhs 并在您的 GHCi 中尝试。
快速解决方案
首先,让我们推理一下 (/2)
的使用。 n * m * (m + 1)
是奇数还是偶数?嗯,要么 m
是奇数,m + 1
是偶数,因此整个乘积是偶数,要么 m
是偶数,同样的论点成立。
所以我们可以使用 n * m * (m + 1) `div` 2
:
而不是 n * m * (m + 1) / 2
> maxFor l n = n * m * (m + 1) `div` 2
> where m = l `div` n
现在,我们所要做的就是检查我们使用的函数的类型:
(+) :: Num a => a -> a -> a
(*) :: Num a => a -> a -> a
div :: Integral n => n -> n -> n
这直接导致您的类型:
> maxFor :: Integral n => n -> n -> n
或者,您可以使用某些特定类型来排除错误:
maxFor :: Integer -> Integer -> Integer
-- Now GHC yells at you since Integer doesn't have a Fractional instance
-- and you try to use (/).
背景资料
您已经认识到问题所在。 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’
这是第一部分。
第二部分源于文字。 999
或 5
的类型为 Num a => a
。现在 GHC 进退两难:它必须找到一个 Num
实例,即 Integral
和 Fractional
。由于没有这样的类型(见上文),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
所以这主要是你最终出现错误的原因。
我对 Haskell 还是个新手,我遇到了一个问题,这个问题应该不难解决,但完全难倒了我。
我写了一个函数:
maxFor l n = n * m * (m + 1) / 2 where m = l `div` n
该函数属于一个加载没有问题的小模块,但每当我在加载该模块后尝试使用该函数时,就会抛出两个对我来说令人尴尬的神秘错误:
<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
我知道它告诉我我的函数缺少正确的类型声明,但我不明白如何在编译器不再唠叨的情况下编写它。我已经尝试了无数种变体,但我不了解实际问题并不能帮助我解决问题。
部分问题可能是我在一个函数中使用了 (/)
和 div
,因此所需的类型声明可能包含 Fractional
and/or Integral
, 因为:
(/) :: Fractional a => a -> a -> a
和:
div :: Integral a => a -> a -> a
但这就是我所知道的,我被卡住了。我将如何编写 maxFor
的类型声明?我究竟做错了什么?我是否遗漏或忽略了一些显而易见的事情?
非常感谢任何帮助和建设性反馈。
编辑:我找到了关于堆栈溢出的 this 答案,这已经有点帮助了。我仍然很感激帮助,但我当然会删除这个问题,如果事实证明我是个白痴并最终被否决。
注:这个post是写在literate Haskell里的。您可以将其保存为 Max.lhs 并在您的 GHCi 中尝试。
快速解决方案
首先,让我们推理一下 (/2)
的使用。 n * m * (m + 1)
是奇数还是偶数?嗯,要么 m
是奇数,m + 1
是偶数,因此整个乘积是偶数,要么 m
是偶数,同样的论点成立。
所以我们可以使用 n * m * (m + 1) `div` 2
:
n * m * (m + 1) / 2
> maxFor l n = n * m * (m + 1) `div` 2
> where m = l `div` n
现在,我们所要做的就是检查我们使用的函数的类型:
(+) :: Num a => a -> a -> a
(*) :: Num a => a -> a -> a
div :: Integral n => n -> n -> n
这直接导致您的类型:
> maxFor :: Integral n => n -> n -> n
或者,您可以使用某些特定类型来排除错误:
maxFor :: Integer -> Integer -> Integer
-- Now GHC yells at you since Integer doesn't have a Fractional instance
-- and you try to use (/).
背景资料
您已经认识到问题所在。 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’
这是第一部分。
第二部分源于文字。 999
或 5
的类型为 Num a => a
。现在 GHC 进退两难:它必须找到一个 Num
实例,即 Integral
和 Fractional
。由于没有这样的类型(见上文),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
所以这主要是你最终出现错误的原因。