haskell-jp / beginners #24 at 2024-05-02 11:25:48 +0900

Haskellを勉強中の学生です。Haskellの美しさに日々感動しながら勉強しているのですが、下の構文だけは美しくないなと思っています。
ghci> :t (+2)
(+2) :: Num a => a -> a
ghci> :t (-2)
(-2) :: Num a => a

みなさんはこの構文についてどのように考えていますか?
この構文に納得できる説明はありますか?また、この構文が導入された背景を知りたいです。
ghci> :t (+ 2)
(+ 2) :: Num a => a -> a
ghci> :t (- 2)
(- 2) :: Num a => a
ghci> :t (/ 2)
(/ 2) :: Fractional a => a -> a
ghci> :t (* 2)
(* 2) :: Num a => a -> a

ghci> :t +2
:1:1: error: parse error on input '+'
ghci> :t -2
-2 :: Num a => a
ghci> :t (+1)
(+1) :: Num a => a -> a
ghci> :t (-1)
(-1) :: Num a => a

演算子の中でマイナスだけを特別扱いするのは仕方のないことだとは思いますが、プラスも同様に使えたり、演算子と値を(直接)つなげるとエラーを吐いたりしてほしいなという気持ちがあります。
それはどちらかというと - だけが例外で「負の数を表すための単項演算子としてのマイナス」の解釈を優先した結果ですね。
一般的には (二項演算子 右側のオペランド) という記法で section と呼ばれますが、たとえば
map (+ 2) [10, 20, 30][12, 22, 32] となる例のように、一引数関数を取る高階関数に対して二項演算子の右側のオペランドを固定して一引数関数となるようにして渡す際に便利な記法です。
逆に map (100 -) [10, 20, 30] のようにすれば [90, 80, 70] となり、左側のオペランドを固定することもできます。
また、 (Haskell 自体の仕様ではありませんが) ghc 処理系の独自拡張では (-2)(- 2) の区別をする機能があります。
https://zenn.dev/mod_poppo/articles/ghc-8-10-and-9-0#lexicalnegation-%E6%8B%A1%E5%BC%B5%E3%81%A8-negativeliterals-%E3%81%AE%E5%A4%89%E6%9B%B4
一方、残念ながら (+2) を「単項プラスつきのただの値」だとみなす記法はたぶんありません…
返信ありがとうございます。
使う人はあまりいないとは思いますが、(+2)が使えたら対称性があってきれいだなあと感じます。これがないのは残念です。
リンク先のLexicalNegation拡張は知らなかったです。これを使えば僕が感じているほとんどの違和感は解消されると思います。やはり(-2)の構文は美しくないと感じる人が多いのでしょうか?
そもそも Haskell には - しか単項演算子がないので、たぶん「単項演算子なんてものは本当は言語機能に導入したくなかった(が、さすがにマイナスは -x とか書きたいのでしょうがなく導入した)」という感じがあります。なので単項プラスは「不要なのだから導入しなかった」ということだと思います
なるほど。必要最低限の仕様にしたいという背景には納得できます。
必要最低限を美しさとするか、対称性を美しさとするかで派閥が分かれそうですね。
もやもやしていた部分がはっきりしてよかったです。ありがとうございました。