运算符作为Haskell中的参数

Vit*_*min 4 haskell operators

我对Haskell很新,可能是一个愚蠢的问题.我想要的是将我的函数作为参数赋予任何运算符.例如:

myFunc :: a -> Int -> Int -> Boolean
myFunc operator a b = a operator b

*Project> myFunc (>) 5 2
True
*Project> myFunc (<=) 5 2
False
Run Code Online (Sandbox Code Playgroud)

请告诉我如何做到这一点!

Maj*_*320 8

你可以用haskell函数参数做到这一点.在上面的函数中,你想要myFunc一个需要两个Ints 的函数并返回一个Bool(不是 a Boolean,你必须键入错误的函数).该职能的声明将是(Int -> Int -> Bool).因此,你可以写:

myFunc :: (Int -> Int -> Bool) -> Int -> Int -> Bool
myFunc op a b = a `op` b
Run Code Online (Sandbox Code Playgroud)

这定义了一个高阶函数,它接受一个带有两个Int返回a Bool(和两个Ints)参数的函数.您现在可以像使用任何其他函数参数一样使用它!

请注意,这与执行完全相同:

myFunc (#) a b = a # b
Run Code Online (Sandbox Code Playgroud)

要么:

myFunc (%) a b = a % b
Run Code Online (Sandbox Code Playgroud)

由于使用中缀则算像*或者/,或任何只对特殊字符组成的运营商,没有反引号只是为了利用他们与速记(输入`/`您想要分割的东西会招人烦,每次!).

  • @leftaroundabout是的,但我认为op的问题是一个明显简化的例子,适用于更大的问题. (3认同)
  • 您需要围绕运算符参数的parens.`myFunc#ab`不解析.如果是这样,它很可能(尝试)定义运算符`(#)`,而不是`myFunc`(例如,`a#b = ...`是`(#)`的定义,而不是`了`).`myFunc(#)ab`会做你的建议. (2认同)
  • `\`/ \``是语法错误.更确切地说,`(`和`)`使一个运算符成为一个函数,而一对```s将一个函数作为一个运算符. (2认同)

Ben*_*Ben 6

在引擎盖下,功能"存在"没有名称.您定义的任何函数(或已在库中定义的函数),例如myFuncjust 一个函数值,该名称只是为我们提供了一种在其他想要使用它的代码中引用它的方法.这与您编写的内容完全相同x = 3:值3"存在"独立于名称x,该名称只是为我们提供了引用它的方法.

为什么这与你关于传递算子的问题有关?

好了,就哈斯克尔而言,像运营商><=碰巧被绑定到名字只是无名的功能><=.它们作为运算符的特殊处理(你可以在它们调用它们的参数之间写入它们)只是关于名称,如果你用不同的名称引用它们就会改变.

Haskell中有两种类型的名称.字母数字名称(仅由字母,数字和下划线组成)和符号名称(仅由符号字符组成).如果你有一个表达式{1} {2} {3},那么如果{2}是一个象征性的名称({1}{3} 不是象征性的名字,否则你有一个语法错误),则表达式被解释为意为"打电话{2}的论点{1}{3}".但是,如果他们都不是符号名称,那么它的,而不是解释为"电话{1}上的争论{2}{3}".1

但所有这些只发生在引用名称时,而不是这些名称实际引用的函数.所以,如果你这样写myFunc:

myFunc operator a b = operator a b
Run Code Online (Sandbox Code Playgroud)

然后,无论是myFunc被称为是喜欢myFunc (+) 1 2还是喜欢myFunc plus 1 2,实际上并不重要; myFunc"operator" 定义中的内容由名称引用,该名称operator是字母数字名称.所以当你想要调用它时,你把它放在第一位,其参数如下.

或者,您可以在里面使用符号名称myFunc,如下所示:

myFunc ($&^*) a b = a $&^* b
Run Code Online (Sandbox Code Playgroud)

同样,即使在myFunc使用非运算符函数调用时,这也可以工作myFunc plus 1 2.

当然,有一些方法可以将任何一种名称转换为另一种名称; 你可以在反引号中加上一个字母数字名称,以便像操作符一样使用它作为中缀:

myFunc operator a b = a `operator` b
Run Code Online (Sandbox Code Playgroud)

并且您可以在括号中放置一个符号名称,只需将其用作对其绑定的函数的引用(实际上这是使用运算符而不为其提供参数的唯一方法):

myFunc ($^&*) a b = ($&^*) a b
Run Code Online (Sandbox Code Playgroud)

所以基本上,你需要知道的将操作符传递给函数的唯一特殊事项是你已经知道的:在调用函数时将操作符放在括号中.在函数的定义中,您可以将其写成与任何其他函数完全相同; 您在该函数定义中选择的名称样式将决定您是将其称为操作符还是普通函数.你不需要知道(实际上找不到)它是否是一个"外部"的操作符.


1当然,当你有更复杂的表达式涉及超过3个事物和多个运算符时,优先级和关联性规则就会发挥作用,以确定究竟发生了什么.