8

我想在 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不与Monomorphism Restriction冲突的实例类型?


编辑-

import qualified

是一个很好的提示,谢谢。

但不幸的是,这迫使我明确地将所有标准方法纳入范围。我只想有可能重新定义某些绑定,而其余的保持不变。

那么有没有两者的结合呢?就像是

import Prelude qualified ((*))
4

4 回答 4

24

回答编辑的问题:

你可以做

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
于 2010-03-05T18:03:36.860 回答
4

实例

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 和所有其他类,这至少会让他们只使用您的新类型包装器。

于 2010-03-07T07:41:50.037 回答
3

有一些尝试做这样的事情。

首先,

如何访问原始 * 运算符(Prelude.(*) 不起作用)

您需要:

import qualified Prelude 

现在您可以使用例如(Prelude.*)。这不如“LANGUAGE NoImplicitPrelude”那么激进,后者也会导致 >>= 等的本地使用反弹到您的定义中。

以下是其他人的替代前奏的示例:

于 2010-03-05T17:34:37.803 回答
2

我可以回答第一个问题。隐藏 (*) 运算符真的隐藏了它,所以你无法得到它。但是,您可以导入 Prelude 限定:

import qualified Prelude as P

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

我认为那可以满足您的要求。

于 2010-03-05T17:40:23.673 回答