Haskell 带有“的语法错误”;infixl";及;infixr";操作员

Haskell 带有“的语法错误”;infixl";及;infixr";操作员,haskell,syntax,operators,operator-precedence,infix-notation,Haskell,Syntax,Operators,Operator Precedence,Infix Notation,我想使用lens更新一个记录,该记录的值由attoparsec解析 fmap (myRecord & _2 . someField .~) double 这完全不起作用: Iddq3.hs:99:48: The operator ‘.~’ [infixr 4] of a section must have lower precedence than that of the operand, namely ‘&’ [infixl 1]

我想使用lens更新一个记录,该记录的值由attoparsec解析

fmap (myRecord & _2 . someField .~) double
这完全不起作用:

Iddq3.hs:99:48:
    The operator ‘.~’ [infixr 4] of a section
        must have lower precedence than that of the operand,
          namely ‘&’ [infixl 1]
        in the section: ‘myRecord & _2 . someField .~’

这个错误意味着什么?什么是
infixr
infixl
?如何重写函数以更正它?

您不能混合这种固定性的运算符。Haskell中的固定性只是运算符优先级,就像你的“请原谅我亲爱的Sally阿姨”(如果你是美国人,这可能是你所学的)记忆操作顺序一样,即括号、指数、乘法、除法、加法、减法。这里,据说
~
运算符的右关联优先级高于
&
运算符的左关联低优先级。真正的问题是混合使用左右关联运算符,编译器不知道应用它们的顺序

相反,您可以将其重新表述为两个操作符部分,它们组合在一起

fmap ((myRecord &) . (_2 . someField .~)) double
因此,您可以为编译器提供一个显式分组,也可以使用prefix
set
函数来获得更清晰的外观

fmap (\v -> set (_2 . someField) v myRecord) double
或者,如果您想摆脱lambda(我的偏好是不去管它),您可以使用
flip
as

fmap (flip (set (_2 . someField)) myRecord) double

这是对在节中使用运算符的方式的一个有点奇怪的限制

基本上,当您有一个像
(e1&e2.~)
这样的运算符节时,有两种方法可以想象将其分解为无节表示法。一种是将运算符转换为前缀位置:

(.~) (e1 & e2)
(如果操作员在前面,还需要添加一个
翻转
。)

另一种方法是将其转换为lambda表达式:

\x -> e1 & e2 .~ x
这两种分段思维方式应该给出相同的结果。 但是,如果像这里一样,存在另一个固定性/优先级低于分段运算符的运算符
&
。因为这意味着lambda表达式解析为

\x -> e1 & (e2 .~ x)
换句话说,lambda表达式肯定不等同于简单地移动操作符,并将其余部分作为统一表达式

虽然Haskell的设计师可以选择用这两种方式中的一种来解释一个部分,但是他们却选择不允许两种解释不匹配的部分,并使它们出错。可能是因为,据我所知,lambda表达式解释对人类来说更直观,而操作符移动更容易在解析器/编译器中实现


但是,您始终可以显式地使用lambda表达式,或者创建自己的无点版本,如@bheklillr所示。

您可以,只是不能像那样混合这些运算符,请尝试
fmap((myRecord&.)(_2.someField.~)double
。正如错误消息所说,问题来自固定性。或者,您可以使用
fmap(\v->set(\u 2.someField)v myRecord)double
,我认为这样看起来更好。@bheklillr谢谢。那看起来真像nicer@Christian康克尔,我是说,我确实读过。但我不知道这是什么意思。你认为我的问题应该是什么?@ChristianConkle。谢谢这样,如果有人将错误粘贴到Google中,他们将有机会找到此错误。右与左与此无关,只有当他们具有相同的数字固定性级别时才适用。再次感谢。我问了一个为什么(0:1:)的lambda表达式\x->0:1:x是等价的?不,
(:)(0:1)
需要等价于
\x->0:1:x
,但它实际上是
\x->(0:1):x
(这没有意义)。