2017-02-28 30 views
5

前綴運算符很好的一個重要原因是它們可以避免使用括號,因此+ - 10 1 2明確表示(10 - 1) + 2。如果parens被丟棄,中綴表達式變得模糊不清,你可以通過具有某些優先規則來消除這種情況,但這很麻煩,等等,等等等等。Haskell:獲得無括號的前綴運算符

我想使Haskell使用前綴操作,但我所見過的唯一方法是通過消除括號來實現這種收益。

Prelude> (-) 10 1 

使用兩個parens。

當您嘗試撰寫功能,因爲

Prelude> (+) (-) 10 1 2 

產生錯誤它會變得更糟,我相信,因爲它試圖喂減法運算進入加操作,而不是首先評估負,然後feeding- - 現在你需要更多的parens!

有沒有辦法讓Haskell智能地評估前綴符號?我想,如果我做了的功能,如

Prelude> let p x y = x+y 
Prelude> let m x y = x-y 

我會恢復較少括號初始收益,但功能成分仍然是一個問題。如果有一種巧妙的方法可以將它與$表示法聯繫起來,使其至少接近我的意願,我就沒有看到它。如果有一個完全不同的戰略可用,我會很高興聽到它。

我試圖重現什麼公認的答案在這裏做的:

Haskell: get rid of parentheses in liftM2

但在這兩種前奏控制檯和一個Haskell腳本,導入命令沒有工作。此外,這是Haskell比我能夠理解的更先進,所以我希望無論如何可能還有其他更簡單的解決方案,然後再進行繁重的調查來調查此類操作。

+3

這不能真正做到,並不是真的有必要。使用更多'let's讓表達更具可讀性。 – Ryan

+5

對於'(+)( - )10 1 2'來說,你需要查找多少個參數'( - )'和'(+)'才能解析。與需要知道固定相比,這看起來更加痛苦。哦,這會造成含有一元'-'的歧義。 – Alec

+0

爲什麼地球上你想使用前綴符號而不是爲它設計的語言?即使它有某種可能性(例如通過quasiquotation或TH),它也只會導致非常單一的代碼。 – chi

回答

5

當您嘗試撰寫功能,因爲

Prelude> (+) (-) 10 1 2 

產生錯誤它會變得更糟,我相信,因爲它是 試圖喂減法運算進入加操作而 不是第一次評估減然後餵食 - 所以現在你甚至需要更多parens!

在這裏,你提出了一個關鍵問題,它是一個阻礙你在Haskell中獲得你想要的東西的攔截器。

您正在討論的前綴表示法對於基本的算術運算(更一般地說,對於任何靜態已知矩陣的函數集)都是明確的。但你必須知道,+-每個接受+ - 10 1 2的兩個參數,明確解析爲+(-(10, 1), 2)(其中我有明確的參數列表來表示每個調用)。

但忽略+-的具體含義,以第二個函數作爲參數的第一個函數是一個完全合理的解釋!對於Haskell而不是算術,我們需要支持更高階的函數,如map。你會想not not x必須變成not(not(x)),但map not x必須變成map(not, x)

如果我有f g x怎麼辦?這應該如何工作?我是否需要知道fg是綁定的,以便我知道它是類似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 etc這樣的術語序列解釋爲((((foo) bar) baz) qux) etc(其中每個foo,bar等可以是括號中的標識符或子項)。你使用圓括號不要明確規定那個規則,但是要分組的條件強加一個不同的調用結構比那個硬性規則會給你的。

綴運算符複雜化這條規則,他們曖昧不知道一些關於所涉及的運營商(他們的優先級和結合,它不像元數與不是實際值稱爲關聯)。這些併發症是爲了使代碼更易於理解而添加的。特別是對於大多數程序員已經熟悉的算術慣例(+*等優先級低)。

如果你不喜歡記憶符的優先級和結合性(不是不合理位置)的額外負擔,你免費使用的符號是明確的,而不需要優先規則,但它有是Haskell的前綴表示法,而不是波蘭語前綴表示法。不管你使用的是什麼語法,在任何語言中,你總是會使用類似括號的東西來表示分組,你所需要的調用結構與標準約定所表示的不同。所以:

(+) ((-) 10 1) 2 

或者:

plus (minus 10 1) 2 

如果定義非運營商的函數名。

+0

的確如此,我想到了這一點,但我認爲有很好的解決方案。首先,我們可以假設所有的操作(與函數相反)都是二進制的,如果我們想區分二進制和一元符號,我們總是可以使用二進制和寫0 1來得到-1。 – Addem

+2

@亞當是的,我想你可以做一些工作。類似於「彼此相鄰的普通術語是應用程序的左聯合鏈,運算符術語啓動波蘭語前綴符號鏈並繼續,直到頭部運算符有2個參數,在波蘭語鏈中,所有非運算符術語都是運算符參數」 。所以你可以說'fmap($)$。 (f arg)。 g(h q(r s))x foo bar'表示Haskellers會拼寫'fmap($)(f arg。g。h q(r s)$ x)foo bar'(I * think * I got that right)。可能的,但絕對不是Haskell! – Ben