在Haskell中使用3-arg中缀运算符的实例?(比如$| |)

在Haskell中使用3-arg中缀运算符的实例?(比如$| |),haskell,parallel-processing,coding-style,infix-operator,Haskell,Parallel Processing,Coding Style,Infix Operator,我在parallel软件包中发现: -- Strategic function application {- These are very handy when writing pipeline parallelism asa sequence of @$@, @$|@ and @$||@'s. There is no need of naming intermediate values in this case. The separation of algorithm from strate

我在
parallel
软件包中发现:

-- Strategic function application

{-
These are very handy when writing pipeline parallelism asa sequence of
@$@, @$|@ and @$||@'s. There is no need of naming intermediate values
in this case. The separation of algorithm from strategy is achieved by
allowing strategies only as second arguments to @$|@ and @$||@.
-}

-- | Sequential function application. The argument is evaluated using
--   the given strategy before it is given to the function.
($|) :: (a -> b) -> Strategy a -> a -> b
f $| s  = \ x -> let z = x `using` s in z `pseq` f z

-- | Parallel function application. The argument is evaluated using
-- the given strategy, in parallel with the function application.
($||) :: (a -> b) -> Strategy a -> a -> b
f $|| s = \ x -> let z = x `using` s in z `par` f z
但他们有三个论点。我还没有看到使用这些运算符的示例,所以我需要想出一个好的方式来编写它们

他们通常的风格是:

f $|| strategy $ expr

优先级和
$
所以Haskell有一个非常规则的语法。最优先的是括号;然后将函数应用于其参数。函数应用程序是左关联的,或者我更喜欢称之为贪婪的nom:这意味着函数“吃掉”了它作为参数看到的第一件东西。因此,如果您先写入
fgh
,这将变成
(fg)h
f
eats
g
,然后返回值eats
h
。通常,特别是在定义函数时,您需要编写类似于
f(构造函数参数1参数2)=……
的内容,其中确实需要显式括号,这样您就不会意外地编写
((f构造函数)参数1)参数2

在括号和应用程序之后,我们有操作符:这些操作符有一个由“中缀指令”给出的优先级和关联性的完整层次结构。最低优先级运算符定义为:

f $ g = f g
infixr 0 $
这个操作符是一个完全正常的操作符,看起来什么都不做:更准确地说,它将其左侧的函数应用于其右侧的参数。它是低优先级右关联的,因此它是“lazy nom”(
$
之前的函数应用于
$
之后的所有函数)。关于是否
f存在一个有趣的语法争论。Gh$i
比f$g$h$i更准确,后者以不同的方式执行相同的操作

请记住,
$
实际上只是一个普通的运算符/函数。例如,您可以执行以下操作:

Prelude> let factorial n = product [1..n]
Prelude> map ($ 3) [(5 +), (3 *), (3 +) . factorial . (2 *)]
[8,9,723]
这里我们创建一个函数
($3)
,它将函数作为参数,并将其应用于3。我们将结果函数映射到其他几个函数上。如果您真的需要,我们也可以将其编写为
zipWith($)函数(重复3)
,将
($)
传递为组合函数,zipWith将使用该函数将两个列表压缩在一起。它们是一样的,而且都是有趣的把戏。有朝一日,您甚至可能希望在值列表上映射(翻转($),以获得函数形式的值列表。这是一个同构;您可以使用
id=map($id)返回值。映射(翻转($)
,但也许有一天这种格式会更方便您

低于此优先级的是特殊形式,如
if
let
case
do
where
\
。通常,Haskell要求这些不能立即出现在值或
之后,但可能出现在
或运算符之后。因此,如果您想写入
f\x->3+2*x
,Haskell将投诉,直到您将其变成以下内容之一:

f ((3 +) . (2 *)) -- no special forms
f (\x -> 3 + 2 * x) -- parenthesize the sub-expression
f $ \x -> 3 + 2 * x -- use $ to make the syntax "work" effortlessly.
类似地,您可能会看到如下情况:

main = complicatedProcessingStep . preprocessing $ do
    input <- io_input
    ...
但是如果类型不是多态的,或者如果您编写了显式类型签名或禁用了“单态限制”,那么您也可以编写类似于
(%%)=mod
的内容

三个参数运算符。 这是关于“三参数运算符”的答案:它返回一个函数,然后可以应用于其他值。当您编写:

a x $|| b y $ c z
根据上述规则,此解析为:

($) (($||) (a x) (b y)) (c z)
根据
($)
的定义,它变成:

($||) (a x) (b y) (c z)
只需在子表达式上使用操作符,
ax$| | b y
,即可生成一个函数,该函数可以使用括号应用,如
(a x$| | b y)(cz)
,或者使用
$
操作符将其左手侧应用到右手侧。

优先级和
$
所以Haskell有一个非常规则的语法。最优先的是括号;然后是将函数应用到它的参数。函数应用程序是左关联的,或者,我更喜欢称之为贪婪的nom:意思是函数“吃光”它在它后面看到的第一件事就是它的参数。因此,如果你写
fgh
,这就变成了
(fg)h
f
首先吃
g
,然后返回值吃
h
。通常,特别是当你定义一个函数时,你想要写一些类似
f的东西(Constructor parameter1 parameter2)=……
其中您确实需要显式括号,这样您就不会意外地编写
((f Constructor)parameter1)parameter2

在括号和应用程序之后,我们有运算符:这些运算符具有由“中缀指令”给出的整个优先级和关联性层次结构。最低优先级运算符定义为:

f $ g = f g
infixr 0 $
此运算符是一个完全正常的运算符,似乎什么都不做:更准确地说,它将其左侧的函数应用于其右侧的参数。它是低优先级的右关联运算符,因此它是“lazy nom”(在
$
之前的函数应用于该
$
之后的所有函数)有一个有趣的语法争论是关于
f.g.h$i
是否比
f$g$h$i
更正确,后者以不同的方式做同样的事情

请记住,
$
实际上只是一个普通的运算符/函数。例如,您可以执行以下操作:

Prelude> let factorial n = product [1..n]
Prelude> map ($ 3) [(5 +), (3 *), (3 +) . factorial . (2 *)]
[8,9,723]
在这里,我们创建一个函数
($3)
,它将一个函数作为其参数,并将其应用于3。我们将结果函数映射到其他几个函数上。如果确实需要,我们也可以将其编写为带($)函数(重复3),传递
($)
作为zipWith将用来将两个列表压缩在一起的组合函数。它们是一样的,而且都是有趣的把戏。你甚至有一天会想要
ma