[英]Defining the associativity of a custom operator in Haskell
我正在使用自定义运算符infix
、 infixl
和infixr
。 现在我很困惑。
我为列表乘法编写了一个自定义运算符,并认为将其声明为没有方向关联性的简单中缀运算符会自动提供nr * list
和list * number
这两种情况,因为它们可以随意互换.
import Prelude hiding ((*))
infix 6 *
(*) :: Int -> [a] -> [a]
n * l
| n < 0 = []
| n == 1 = l
| otherwise = l ++ (n - 1) * l
现在, 3 * [1, 2, 3]
[1, 2, 3, 1, 2, 3, 1, 2, 3]
,但是[1, 2, 3] * 3
抛出错误,因为我从未明确定义list * nr
。
我的问题:中infix
的独特功能是什么,为什么不总是使用中infixl
或中infixr
,因为它应该没有区别?
我将“无方向关联性”/中infix
理解为“可交换”的同义词:
a + b + c
has no directional associativity or is commutative and can be written as (a + b) + c
, a + (b + c)
, b + a + c
, (b + a) + c
, and so on ...
对于我的示例2 * [1, 2] * 1
与1 * 2 * [1, 2]
以及所有其他排列相同,所以我真的不明白为什么对交换运算符声明没有隐式重塑,即使使用不同类型的操作数。
固定性声明仅影响解析,而不影响运算符的定义。
如果使用infixl
,则a * b * c
被解析为(a * b) * c
。
如果您使用infixr
,则a * b * c
被解析为a * (b * c)
。
如果您使用infix
,那么您是在说a * b * c
无法解析; 您必须使用括号来指定您的意思是(a * b) * c
还是a * (b * c)
。
在您的情况下, *
不是完全关联的,因为类型不对齐。 它可以是右关联的,因为3 * (6 * [])
类型检查但不是左关联的,因为(3 * 6) * []
没有。 使用中infix
,您不允许3 * 6 * []
。 如果您使用infixr
,那么您可以编写它,解析器会将其视为3 * (6 * [])
。
使这样的可交换运算符很棘手,因为在类型级别它们是两个不同的运算符。 这很容易定义:
-- Ignoring the fact that both of these operators are already
-- used by the Applicative class for different purposes.
(*>) :: Int -> [a] -> [a]
0 *> l = []
n *> l = l ++ (n-1) * l
(<*) :: [a] -> Int -> [a]
(<*) = flip (*>)
让*
作为Int -> [a] -> [a]
和[a] -> Int -> [a]
工作是很棘手的,如果不是不可能的话。 (也许涉及多参数类型族?
-- Compiles, but does not run. Not sure why...
{-# LANGUAGE TypeFamilies, MultiParamTypeClasses, FlexibleContexts #-}
class Multiplable x y where
type Result x y
(***) :: x -> y -> Result x y
instance Multiplable Int [a] where
type Result Int [a] = [a]
0 *** l = []
n *** l = l ++ ((n - 1) *** l)
instance Multiplable [a] Int where
type Result [a] Int = [a]
l *** 0 = []
l *** n = l ++ (l *** (n - 1))
)
您对关联性和交换性的理解是不正确的。 “不结合”不是“交换”的同义词。 事实上,这两个属性是正交的:给定的运算符可以是两者,也可以不是,或者只是两者之一。
Integer 加法是关联和交换的。
Integer 减法既不结合也不可交换。
矩阵乘法是关联的,但不是可交换的。 ( BA
可以与AB
不同,甚至完全未定义。)
与非运算(逻辑与的否定)是可交换的,但不是结合的:
(True NAND True) NAND False == False NAND False == True True NAND (True NAND False) == True NAND True == False
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.