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 ((*))
8
задан Dario 5 March 2010 в 17:50
поделиться

4 ответа

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

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

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
23
ответ дан 5 December 2019 в 05:18
поделиться

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

Во-первых,

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

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

import qualified Prelude 

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

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

3
ответ дан 5 December 2019 в 05:18
поделиться

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

import qualified Prelude as P

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

Я думаю, это то, что вам нужно.

2
ответ дан 5 December 2019 в 05:18
поделиться

Экземпляр

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

В значительной степени уничтожит цель определения Mul t 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 и все остальные классы самостоятельно.

4
ответ дан 5 December 2019 в 05:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: