Haskell-переопределение (скрытие) арифметических операторов

Я хочу переопределить несколько арифметических операторов в Haskell, чтобы сделать их более расширяемыми и общими.

Э. Г.

class Mul a b c | a b -> c where
    (*) :: a -> b -> c

это, кажется, работает в сочетании с

import Prelude hiding ((*))

скрытие стандарта * оператора. Но, конечно, все обычные умножения также должны работать, поэтому мне нужно определить что-то вроде

instance (Num t) => Mul t t t where
    (*) = ??

как я могу получить доступ к исходной * оператор (Prelude.(*) не работает) здесь и как я могу необходимо определить тип экземпляра так, чтобы 1 * 1 не конфликтует с Ограничение Monomorpism?


редактировать -

import qualified

хороший совет, спасибо.

но, к сожалению, это заставило меня принести все стандартные методы в области явно. Я просто хочу иметь возможность переопределить некоторые привязки, оставив остальные без изменений.

Итак, есть ли комбинация обоих? Что-то вроде

import Prelude qualified ((*))

4 ответов


ответ на отредактированный вопрос:

можно сделать

import Prelude hiding ((*))
import qualified Prelude as P

чтобы получить доступ ко всем функциям прелюдии, кроме (*) обычным способом и до (*) через P префикс:

x = 5 + 3   -- works
y = 5 P.* 3 -- works
z = 5 * 3   -- complains about * not being in scope

экземпляр

instance (Num t) => Mul t t t where
    (*) = ??

в значительной степени победит цель определения Mul t t t в первую очередь, без злоупотребления расширениями, чтобы позволить {-# LANGUAGE OverlappingInstances #-}.

к сожалению, "правильный", если болезненный ответ должен пройти экземпляр за экземпляром и сделать

import Prelude hiding ((*))
import qualified Prelude 

instance Mul Int Int Int where
    (*) = (Prelude.*)

instance Mul Double Double Double where
    (*) = (Prelude.*)


instance Mul Int Double Double where
    ...

instance Mul (Complex Float) (Complex Double) (Complex Double)
    ...

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

тем не менее, вы можете, по крайней мере, облегчить боль для случаев, о которых вы не думали:

newtype Other a = Other a

instance Num a => Mul (Other a) (Other a) (Other a) where
    Other a * Other b = Other (a Prelude.* b)

это, по крайней мере, позволит им просто использовать вашу оболочку newtype, если они не хотят идти и определять Mul и все ваши другие классы сами.


было несколько попыток сделать такие вещи.

во-первых,

Как я могу получить доступ к исходному оператору * (прелюдия.(*) не работает)

вам потребуется:

import qualified Prelude 

теперь вы можете использовать, например, (Prelude.*). Это менее агрессивно, чем" язык NoImplicitPrelude", который также приведет к локальному использованию >>= и так далее, чтобы отскочить от ваших определений.

вот примеры альтернативы других людей прелюдии:


Я могу ответить на первый вопрос. Скрытие оператора ( * ) действительно скрывает его, поэтому вы не можете добраться до него. Тем не менее, вы можете импортировать прелюдию квалифицированный:

import qualified Prelude as P

foo = 3 P.* 14 -- == 42

Я думаю, что это делает то, что вы хотите.