如何在Haskell中创建运算符?

32
制作三元逻辑表格,并且我想为一个被称为<=>的运算符编写自己的函数。例如,我想做到这一点,但那样不正确。正确的方法是什么?
data Ternary = T | F | M
deriving (Eq,  Show, Ord)

<=> :: Ternary -> Ternary -> Ternary
<=> T F = F
<=> T T = T
<=> T M = M
<=> F F = T
<=> F T = F
<=> F M = M
<=> M F = M
<=> M T = M
<=> M M = T

3
顺便提一下,M <=> M 应该是 M 而不是 T。但这取决于你的“也许”语义。 - bitmask
不要忘记,你可以使用infixlinfixr等来设置参数个数和结合性。 - Landei
4个回答

50

只需在运算符周围添加括号:

(<=>) :: Ternary -> Ternary -> Ternary
(<=>) T F = F
(<=>) T T = T
(<=>) T M = M
(<=>) F F = T
(<=>) F T = F
(<=>) F M = M
(<=>) M F = M
(<=>) M T = M
(<=>) M M = T

这将把它从中缀形式转换为前缀形式。或者,您可以在定义中直接使用中缀:

(<=>) :: Ternary -> Ternary -> Ternary
T <=> F = F
T <=> T = T
T <=> M = M
F <=> F = T
F <=> T = F
F <=> M = M
M <=> F = M
M <=> T = M
M <=> M = T

有没有办法创建类似于:连接符的东西? :连接符具有这种特殊功能,即将右侧的所有内容视为列表。我一直在尝试重新创建运算符,但它始终需要在右侧使用括号。 - CMCDragonkai
@ClarkGaebel:也许提到infix会更有趣? - Willem Van Onsem
@CMCDragonkai,你也可以用以下方式自己实现相同的功能:data List a = Nil | a :- List a,然后是关键部分:infixr 5 :-。不一定要是5,但这是列表的优先级,只需要是infixr而不是infixlinfixinfixl 9是默认值。 - semicolon

12

带符号的函数名与没有符号的函数名有不同的语法:

-- Works:
(<^>) :: Int -> Int -> Int
a <^> b = a + b

-- Doesn't work:
{-
<^> :: Int -> Int -> Int
<^> a b = a + b
-}

-- Works:
letters :: Int -> Int -> Int
letters a b = a + b

-- Doesn't work:
{-
(letters) :: Int -> Int -> Int
a letters b = a + b
-}

我保证 - 学习 Haskell 虽然需要掌握复杂的规则,但它非常值得学习。

2
你可以将定义简化(逐行)如下:

您可以逐行简化定义如下:

(<=>) :: Ternary -> Ternary -> Ternary
T <=> T = T
F <=> F = T
M <=> M = T
M <=> _ = M
_ <=> M = M
_ <=> _ = F

在我看来,那看起来并不更简单。 - Clark Gaebel
这就是为什么我在那里加了一个(逐行)。然而,清晰度是有争议的。因为我被迫推断它实际上是做什么,而不是看一个原始的表格定义,所以我可以更好地看到代码。但这只是我的看法。 - Thomas Eding
1
在我看来,这样更简单:如果它们相等,则立即返回true;如果它们不相等但其中一个是maybe,则返回maybe;如果它们既不相等也不包含maybe,则返回false。唯一可能让我感到惊讶的部分是M<=>M等于T的部分。 - semicolon

1

由于您拥有EqOrd,因此您可以执行以下操作:

data Ternary = T | F | M
deriving (Eq, Show, Ord)

(<=>) :: Ternary -> Ternary -> Ternary
x <=> y = if x == y then T else max x y

如果你确实改变了它,使得 M <=> M == M 成立,那么你可以按照以下步骤操作:
data Ternary = M | T | F
deriving (Eq, Show, Ord, Enum)

(<=>) :: Ternary -> Ternary -> Ternary
x <=> y = fromEnum $ rem (toEnum x * toEnum y) 3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接