Haskell:获取一个没有括号的前缀运算符

Add*_*dem 6 haskell

前缀运算符很好的一个重要原因是它们可以避免使用括号,以便+ - 10 1 2明确表示(10 - 1) + 2.如果丢弃了parens,那么中缀表达式会变得模棱两可,你可以通过使用某些优先级规则来消除这种情况,但那是凌乱的,等等,等等等等.

我想让Haskell使用前缀操作,但是我看到这样做的唯一方法就是通过删除括号来获得收益.

Prelude> (-) 10 1 
Run Code Online (Sandbox Code Playgroud)

使用两个parens.

当你尝试编写函数时会变得更糟

Prelude> (+) (-) 10 1 2 
Run Code Online (Sandbox Code Playgroud)

产生错误,我相信因为它试图将减号操作送入加号操作,而不是先评估减号然后再喂食 - 所以现在你需要更多的parens!

有没有办法让Haskell智能地评估前缀表示法?我想如果我做了类似的功能

Prelude> let p x y = x+y
Prelude> let m x y = x-y
Run Code Online (Sandbox Code Playgroud)

我会在较少的parens上恢复初始收益,但功能构成仍然是一个问题.如果有一种聪明的方式来加入这个$符号,使其表现至少接近我想要的,我没有看到它.如果有一个完全不同的策略,我很感激听到它.

我试着复制这里接受的答案:

Haskell:摆脱liftM2中的括号

但是在Prelude控制台和Haskell脚本中,import命令都不起作用.此外,这是比我能够理解的更先进的Haskell,所以我希望在我做重任之前可能还有其他更简单的解决方案来调查这是做什么的.

Ben*_*Ben 6

当你尝试编写函数时会变得更糟

Prelude> (+) (-) 10 1 2 
Run Code Online (Sandbox Code Playgroud)

产生错误,我相信因为它试图将减号操作送入加号操作,而不是先评估减号然后再喂食 - 所以现在你需要更多的parens!

在这里,你提出了一个关键问题,它是阻止你在Haskell中获得你想要的东西.

您所讨论的前缀表示法对于基本算术运算(更一般地说,对于静态已知的arity的任何函数集)是明确的.但是你必须知道这一点+并且-每个接受2个参数+ - 10 1 2都要明确地解析为+(-(10, 1), 2)(其中我有明确的参数列表来表示每个调用).

但忽略了+和的具体含义,-第二个函数作为参数的第一个函数是一个非常合理的解释!对于Haskell而不是算术,我们需要支持更高阶函数map.你可能想要not not x变成not(not(x)),但map not x必须变成map(not, x).

如果我有f g x什么?这应该怎么样?我需要知道什么f,并g绑定到,让我知道它是否就像一个情况not not x或类似的情况map not x,只是知道如何解析调用结构?即使假设我有所有可用的代码可供检查,如果我不知道任何表达式的调用结构是什么,我该怎么想弄清楚什么是绑定的?

你会最终需要创造歧义的语法一样map (not) x,包裹not在括号中禁用它的行动像元数-1功能的能力(很象Haskell的实际语法可以让你用小括号括运营商禁止他们表现得像一个中缀操作能力) .或者使用所有Haskell函数都是arity-1的事实,但是你必须编写(map not) x并且你的算术示例必须看起来像(+ ((- 10) 1)) 2.回到括号!

事实是,你提出的前缀表示法并不明确.Haskell的正常函数语法(没有运算符) ; 规则是你总是解释一系列术语,如foo bar baz qux etcas ((((foo) bar) baz) qux) etc(foo,bar等中的每一个都可以是括号中的标识符或子项).您使用括号不消除该规则的歧义,而是将术语分组以强制使用硬规则不同的调用结构.

缀运算符复杂的是规则,他们不知道的东西所涉及的运营商(他们的优先级和结合,它不像元数与相关联的暧昧的名字没有提到实际值).添加了这些复杂性以帮助使代码更容易理解; 特别是对于大多数程序员已经熟悉的算术约定(+优先级低于*等等).

如果你不喜欢必须记住运算符的优先级和关联性(不是一个不合理的位置)的额外负担,你可以自由地使用一个明确的符号而不需要优先级规则,但它必须是Haskell的前缀表示法,不是波兰语前缀表示法.无论你使用什么语法约定,在任何语言中,你总是必须使用括号之类的东西来表示你需要的调用结构与标准约定所指示的不同的分组.所以:

(+) ((-) 10 1) 2
Run Code Online (Sandbox Code Playgroud)

要么:

plus (minus 10 1) 2
Run Code Online (Sandbox Code Playgroud)

如果您定义非运算符函数名称.

  • @Adam是的,我想你可以做点工作.类似"彼此相邻的普通术语是应用程序的左关联链,运算符术语启动波兰语前缀表示链并继续直到头部运算符有2个参数,在波兰链中所有非运算符术语都是运算符参数" .所以你可以说`fmap($)$.(f arg).g(hq(rs))x foo bar`用于什么Haskellers拼写`fmap($)(f arg.gq hq(rs)$ x)foo bar`(我认为*我做对了).可能,但绝对不是Haskell! (2认同)