46

Haskell での演算子と関数の優先順位について、自分で何かを検証しようとしています。たとえば、次のコード

list = map foo $ xs

として書き換えることができます

list = (map foo) $ (xs)

そして最終的には

list = map foo xs

私の質問は、なぜ最初の定式化が次のように書き直されないのかということでした。

list = (map foo $) xs

関数の優先順位は常に演算子の優先順位よりも高いため、答えを見つけたと思います: 演算子を関数の引数にすることはできません (もちろん、括弧で囲む場合を除きます)。これは正しいですか?もしそうなら、RWH や Learn you a Haskell、または私が検索した他の場所のいずれにも、このメカニズム/ルールについての言及がないのは奇妙だと思います。そのため、ルールが記載されている場所を知っている場合は、リンクしてください。

-- 編集: 素早い回答ありがとうございます。私の混乱は、演算子リテラルが何らかの形で評価され、関数によって引数として消費される可能性があると考えたことから生じたと思います。中置演算子は機械的に前置関数に変換できることを思い出すのに役立ちました。これを最初の定式化に対して行うと、

($) (map foo) (xs)

($) が消費関数であることは疑いの余地がなく、2 つの定式化が同等であるため、最初の定式化の $ リテラルは map によって消費されません。

4

5 に答える 5

39

まず、適用 (空白) は最も優先度の高い「演算子」です。

第二に、Haskell では、演算子はデフォルトで中置であるのに対し、関数はそうでないという点を除けば、実際には演算子と関数の間に区別はありません。バッククォートを使用して関数をインフィックスに変換できます

2 `f` x

演算子を括弧付きのプレフィックスに変換します。

(+) 2 3

したがって、あなたの質問は少し混乱しています。

これで、特定の関数と演算子が優先順位を宣言されます。これは、GHCi で ":info" を使用して見つけることができます。

Prelude> :info ($)
($) :: (a -> b) -> a -> b   -- Defined in GHC.Base

infixr 0 $

Prelude> :info (+)

class (Eq a, Show a) => Num a where
  (+) :: a -> a -> a

infixl 6 +

優先順位と結合性の両方を示します。

于 2010-06-26T20:30:52.703 に答える
28

あなたは正しいです。このルールは、Haskell Reportで定義された Haskell 構文の一部です。特に、セクション 3「式」で、関数適用 (an fexp) の引数は an でなければならないことに注意してaexpください。aexp では、セクションの一部として演算子を使用できます。また、括弧で囲まれた式内でも使用できますが、裸の演算子は使用できません。

ではmap foo $ xs、Haskell 構文は、これが 2 項演算子に適用される 2 つの式として解析されることを意味します$。sepp2k が指摘しているように、構文(map foo $)は左側のセクションであり、意味が異なります。

私はこれについてあまり考えたことがなかったことを告白しなければならず、実際にレポートでそれを調べて、オペレーターがなぜ彼らの行動をとるのかを確認する必要がありました.

于 2010-06-26T21:56:38.027 に答える
25

すでに他の回答で提供されている情報に加えて、異なる演算子は他の演算子よりも異なる優先順位を持つことができ、左/右または非結合であることに注意してください。Prelude演算子のこれらのプロパティは、 Haskell 98 レポートの固定性セクションにあります。

+--------+----------------------+----------------- ------+-------------------+
| | 精密 | 左連想 | 非関連 | 右連想 |
| | エデンス | 演算子 | 演算子 | 演算子 |
+--------+----------------------+----------------- ------+-------------------+
| | 9 | !! | | | | . | |
| | 8 | | | | | ^、^^、** |
| | 7 | *, /, `div`, | | | | |
| | | | `mod`, `rem`, `quot` | | | | |
| | 6 | +, - | | | | |
| | 5 | | | | | :, ++ |
| | 4 | | | ==, /=, <, <=, >, >=, | | |
| | | | | | `elem`, `notElem` | | |
| | 3 | | | | | && |
| | 2 | | | | | || | |
| | 1 | >>、>>= | | | | |
| | 0 | | | | | $, $!, `seq` |
+--------+----------------------+----------------- ------+-------------------+

固定性宣言がない演算子は、優先順位 9 で連想のままであると見なされます。

関数適用の優先順位が最も高いことに注意してください (10表の他の優先順位と比較した優先順位を考えてください) [1]

于 2015-05-17T16:05:31.290 に答える
12

違いは、中置演算子が引数の間に配置されることです。

list = map foo $ xs

接頭辞形式で次のように書き換えることができます

list = ($) (map foo) xs

これは、$ 演算子の定義により、単純に

list = (map foo) xs
于 2010-06-26T20:33:39.040 に答える
10

演算子を括弧で囲むと、関数の引数として渡すことができます (つまりmap foo ($) xs、実際には として渡されます(map foo ($)) xs)。ただし、それらを括弧で囲まないと、それらを引数として渡す (または変数に割り当てる) ことはできません。

また、構文(someValue $)(where$は任意の演算子である可能性があります) は実際には別のことを意味することに注意してください。これは と同等です\x -> someValue $ x。つまり、演算子をその左のオペランドに部分的に適用します ($もちろん of の場合は noop です)。同様($ x)に、演算子を右側のオペランドに部分的に適用します。したがって、map ($ x) [f, g, h]と評価され[f x, g x, h x]ます。

于 2010-06-26T20:29:42.987 に答える