Haskell - Переопределение (скрытие) арифметических операторов - PullRequest
8 голосов
/ 05 марта 2010

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

* 1003 Е.Г. *

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 не конфликтовал с Ограничением мономорфизма ?

<Ч />

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

import qualified

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

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

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

import Prelude qualified ((*))

Ответы [ 4 ]

23 голосов
/ 05 марта 2010

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

Вы можете сделать

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

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

x = 5 + 3   -- works
y = 5 P.* 3 -- works
z = 5 * 3   -- complains about * not being in scope
4 голосов
/ 07 марта 2010

Экземпляр

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)

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

3 голосов
/ 05 марта 2010

Было несколько попыток сделать что-то подобное.

Во-первых,

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

Вам понадобится:

import qualified Prelude 

теперь вы можете использовать, например, (Prelude. *).Это менее агрессивно, чем «LANGUAGE NoImplicitPrelude», которое также приведет к тому, что локальное использование >> = и т. Д. Будет привязано к вашим определениям.

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

2 голосов
/ 05 марта 2010

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

import qualified Prelude as P

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

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

...