Я хочу переопределить несколько арифметических операторов в 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 ((*))
Ответ на отредактированный вопрос:
Вы можете сделать
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
Было несколько попыток сделать что-то подобное.
Во-первых,
Как я могу получить доступ к оригинальному оператору * (Prelude.(*) не работает)
Вам понадобится:
import qualified Prelude
теперь вы можете использовать, например, (Prelude.*). Это менее агрессивно, чем "LANGUAGE NoImplicitPrelude", который также приведет к тому, что локальные использования >>= и т.д. будут возвращены в ваши определения.
Вот примеры чужих альтернативных прелюдий:
Я могу ответить на первый вопрос. Скрытие оператора (*) действительно скрывает его, поэтому вы не можете до него добраться. Однако вы можете импортировать Prelude с квалификацией:
import qualified Prelude as P
foo = 3 P.* 14 -- == 42
Я думаю, это то, что вам нужно.
Экземпляр
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 и все остальные классы самостоятельно.