从运算符推断类型类别

发布于 2024-12-02 08:22:15 字数 213 浏览 1 评论 0原文

如果我使用 + 运算符,Haskell 会自动推断类型类 Num

> let add x y = x + y
> :t add
add :: Num a => a -> a -> a

这是否意味着我不能使用 + 运算符拥有多个类型类?

If I use the + operator, Haskell automatically infers the type class Num:

> let add x y = x + y
> :t add
add :: Num a => a -> a -> a

Does this mean I cannot have multiple type classes with a + operator?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

夜光 2024-12-09 08:22:15

在同一个模块中不能有多个定义 + 的类型类(当然这同样适用于任何其他函数名称 - 不仅仅是 +)。

如果您导入多个定义 + 的模块(无论它是否作为类型类的一部分),则在导入除其中一个之外的所有模块时,您需要隐藏 +,将除其中一个之外的所有内容导入为合格的,或者始终引用 + 合格的。

You can't have multiple type classes defining + in the same module (the same applies to any other function name of course - not just +).

And if you import multiple modules which define + (whether it be as part of a typeclass or not), you either need to hide + when importing all but one of them, import all but one of them as qualified or always refer to + qualified.

弥枳 2024-12-09 08:22:15

请注意,+ 与其说是一个运算符,不如说它是一个函数,默认为中缀定位。这意味着它遵循与所有其他函数相同的作用域规则,以及与类型类相同的行为。

具体来说,类型类定义了许多函数,这些函数在实例化该特定类型类的所有类型中都是多态的。因此,给定 Num 的定义为:

class (Eq a, Show a) => Num a where
  (+) :: a -> a -> a
  (*) :: a -> a -> a
  (-) :: a -> a -> a
  negate :: a -> a
  abs :: a -> a
  signum :: a -> a
  fromInteger :: Integer -> a

我们可以得出结论,任何在其范围内包含 Num 定义的东西 - 例如任何导入 Prelude 的东西,但没有Num 的限定或排除 — 在函数 (+) 的范围内已经有定义;这是一个带有类型签名 a ->; 的普通函数。一个-> a,并且语法糖倾向于被假定为中缀,因此您可以编写 x + y 而不是 + x y

特别是,所有这些意味着就像您不能让 fmap 成为由类型类 Functor 和其他类型类定义的函数一样,您也不能+Num 和其他类型类定义。

如果你确实想在其他地方定义它,你总是可以导入相应的限定模块——但是,当你导入它们时,默认为 infix 的非字母函数名称也会变得非常笨拙。您最终会编写类似 3 M.+ 4 而不是 3+4 的内容。

Note that + is not so much an operator as it is a function which defaults to infix positioning. This means that it obeys the same kind of scoping rules as all other functions, and the same behaviour with typeclasses.

Specifically, a typeclass defines a number of functions that are polymorphic across all types that instantiate that particular typeclass. So given the definition of Num as:

class (Eq a, Show a) => Num a where
  (+) :: a -> a -> a
  (*) :: a -> a -> a
  (-) :: a -> a -> a
  negate :: a -> a
  abs :: a -> a
  signum :: a -> a
  fromInteger :: Integer -> a

we can conclude that anything that includes a definition of Num in its scope — such as anything importing Prelude without qualification or exclusion of Num — will already have a definition in scope for the function (+); which is an ordinary function with type signature a -> a -> a, and a syntactic sugar tendency to be assumed infix, so that you'd write x + y instead of + x y.

In particular, all of this means that just as you can't have fmap be a function defined both by the typeclass Functor and by some other typeclass, you also can't have + be defined both by Num and by some other typeclass.

If you do want to define it elsewhere, you can always import the corresponding module qualified — however, the non-alphabetic function names that default to infix also end up really clumsy when you import them qualified. You'd end up writing things like 3 M.+ 4 instead of 3+4.

演多会厌 2024-12-09 08:22:15

我认为问题是是否可以有多类运算符。这听起来像是对类型类如何工作的误解。如果您想实现向量空间之类的东西,其中参数具有不同的类型,您可能需要搜索类型族扩展:

(.*) :: VectorSpace v => Scalar v -> v -> v

对于使用此方法的库,请参阅 向量空间 包。

I think the question is whether it's possible to have multi-class operators. This sounds like a misunderstanding of how type classes work. You may want to search for the type families extension, if you want to implement something like vector spaces, where the arguments have different types:

(.*) :: VectorSpace v => Scalar v -> v -> v

For a library using this approach see the vector-space package.

不爱素颜 2024-12-09 08:22:15

您可以使用 + 运算符拥有多个类型类,只是 Num 类实现是通过 Prelude 隐式导入的。添加语言扩展

{-# LANGUAGE NoImplicitPrelude #-}

或添加一行

import Prelude hiding ((+))

如果您想要一个包含两个类型类的 + ,例如 NumA,那么您可以创建封装两者的新类型类,

import Prelude hiding (id, (.), (+))
import qualified Prelude
import qualified A

class GeneralPlus a where (+) :: a -> a -> a
instance Num a => GeneralPlus a where (+) = (Prelude.+)
instance A a => GeneralPlus a where (+) = (A.+)

You can have multiple type classes with the + operator, it's just that the Num class implementation is imported implicitly via the Prelude. Either add the language extension

{-# LANGUAGE NoImplicitPrelude #-}

or add a line

import Prelude hiding ((+))

If you want a + that includes two type classes, say Num and A, then you could create a new typeclass that encapsulates both,

import Prelude hiding (id, (.), (+))
import qualified Prelude
import qualified A

class GeneralPlus a where (+) :: a -> a -> a
instance Num a => GeneralPlus a where (+) = (Prelude.+)
instance A a => GeneralPlus a where (+) = (A.+)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文