【发布时间】:2017-10-31 16:08:50
【问题描述】:
所以,我正在尝试编写自己的 Prelude 替代品,并且我已将 (^) 实现为这样:
{-# LANGUAGE RebindableSyntax #-}
class Semigroup s where
infixl 7 *
(*) :: s -> s -> s
class (Semigroup m) => Monoid m where
one :: m
class (Ring a) => Numeric a where
fromIntegral :: (Integral i) => i -> a
fromFloating :: (Floating f) => f -> a
class (EuclideanDomain i, Numeric i, Enum i, Ord i) => Integral i where
toInteger :: i -> Integer
quot :: i -> i -> i
quot a b = let (q,r) = (quotRem a b) in q
rem :: i -> i -> i
rem a b = let (q,r) = (quotRem a b) in r
quotRem :: i -> i -> (i, i)
quotRem a b = let q = quot a b; r = rem a b in (q, r)
-- . . .
infixr 8 ^
(^) :: (Monoid m, Integral i) => m -> i -> m
(^) x i
| i == 0 = one
| True = let (d, m) = (divMod i 2)
rec = (x*x) ^ d in
if m == one then x*rec else rec
(注意这里使用的 Integral 是我定义的,不是 Prelude 中的,虽然类似。另外,one 是一个多态常数,它是幺半群运算下的恒等。)
数值类型是幺半群,所以我可以尝试做,比如 2^3,但是类型检查器给了我:
*AlgebraicPrelude> 2^3
<interactive>:16:1: error:
* Could not deduce (Integral i0) arising from a use of `^'
from the context: Numeric m
bound by the inferred type of it :: Numeric m => m
at <interactive>:16:1-3
The type variable `i0' is ambiguous
These potential instances exist:
instance Integral Integer -- Defined at Numbers.hs:190:10
instance Integral Int -- Defined at Numbers.hs:207:10
* In the expression: 2 ^ 3
In an equation for `it': it = 2 ^ 3
<interactive>:16:3: error:
* Could not deduce (Numeric i0) arising from the literal `3'
from the context: Numeric m
bound by the inferred type of it :: Numeric m => m
at <interactive>:16:1-3
The type variable `i0' is ambiguous
These potential instances exist:
instance Numeric Integer -- Defined at Numbers.hs:294:10
instance Numeric Complex -- Defined at Numbers.hs:110:10
instance Numeric Rational -- Defined at Numbers.hs:306:10
...plus four others
(use -fprint-potential-instances to see them all)
* In the second argument of `(^)', namely `3'
In the expression: 2 ^ 3
In an equation for `it': it = 2 ^ 3
我知道这是因为 Int 和 Integer 都是 Integral 类型,但是为什么在普通 Prelude 中我可以做到这一点呢? :
Prelude> :t (2^)
(2^) :: (Num a, Integral b) => b -> a
Prelude> :t 3
3 :: Num p => p
Prelude> 2^3
8
即使我的部分应用的签名看起来相同?
*AlgebraicPrelude> :t (2^)
(2^) :: (Numeric m, Integral i) => i -> m
*AlgebraicPrelude> :t 3
3 :: Numeric a => a
我要怎样才能让 2^3 实际上起作用,从而得到 8?
【问题讨论】:
-
如果我运行你的程序,我只会得到
Ambiguous occurrence ‘^’。您不能简单地覆盖 Haskell 中的名称 -
在我的代码中,我使用了 RebindableSyntax。 Prelude 的 (^) 不在范围内。编辑:另外,我使用的 Monoid 类型类也是我的。
-
如果有帮助,我正在使用的代码都在这个 GitHub 存储库中:github.com/Crazycolorz5/AlgebraicPrelude/tree/…
-
我怀疑这是由于
Num在默认规则中的特殊性,尽管非常感谢 MVCE(因为我可以运行独立的东西来复制问题)。 -
@Alec 我认为你是对的;您知道在 Prelude 代码中指定默认值的位置,以及我如何自己定义它们吗?另外,很抱歉缺少 MVCE,有很多相互关联的代码;我链接的 repo 中的 Groups、Order 和 Numbers 模块应该是重新创建它所必需的。
标签: haskell type-inference exponentiation monoids hindley-milner