Вывод класса типа из оператора - PullRequest
3 голосов
/ 30 августа 2011

Если я использую оператор +, Haskell автоматически выводит класс типа Num:

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

Означает ли это, что я не могу иметь несколько классов типов с оператором +?

Ответы [ 4 ]

9 голосов
/ 30 августа 2011

Вы не можете иметь несколько классов типов, определяющих + в одном и том же модуле (то же самое относится, конечно, к любому другому имени функции - не только к +).

И если вы импортируете несколько модулей, которые определяют + (независимо от того, является ли он частью класса типов или нет), вам нужно либо скрыть + при импорте всех, кроме одного, импортировать все, кроме одного, как квалифицированный или всегда ссылающийся на + квалифицированный.

3 голосов
/ 30 августа 2011

Обратите внимание, что + - это не столько оператор , сколько функция , которая по умолчанию использует инфиксное позиционирование. Это означает, что он подчиняется тем же правилам области видимости, что и все другие функции, и тому же поведению с классами типов.

В частности, класс типов определяет ряд функций, которые полиморфны для всех типов, которые создают этот конкретный класс типов. Итак, учитывая определение 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 -> a и синтаксической склонностью к сахару, предполагаемой инфиксной, так что вы должны написать x + y вместо + x y.

В частности, все это означает, что точно так же, как fmap не может быть функцией, определяемой как классом типов Functor, так и некоторым другим классом типов, вы также не можете определять + как Num и другим классом типов.

Если вы хотите определить его в другом месте, вы всегда можете импортировать соответствующий квалифицированный модуль - однако имена неалфавитных функций, которые по умолчанию инфицированы, также оказываются действительно неуклюжими, когда вы импортируете их квалифицированными. В итоге вы бы написали что-то вроде 3 M.+ 4 вместо 3+4.

0 голосов
/ 31 августа 2011

Вы можете иметь несколько классов типов с помощью оператора +, просто реализация класса Num импортируется неявно через Prelude.Либо добавьте расширение языка

{-# LANGUAGE NoImplicitPrelude #-}

или добавьте строку

import Prelude hiding ((+))

Если вы хотите +, который включает два класса типов, скажем Num и A, тогдаВы можете создать новый класс типов, который будет инкапсулировать оба,

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.+)
0 голосов
/ 30 августа 2011

Я думаю, вопрос в том, возможно ли иметь операторы мультикласса.Это звучит как недопонимание того, как работают классы типов.Вы можете искать расширение семейств типов, если хотите реализовать что-то вроде векторных пространств, где аргументы имеют разные типы:

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

Для библиотеки, использующей этот подход, см. Вектор пробел пакет.

...