web-dev-qa-db-ja.com

一部の関数型プログラミング言語が関数の適用にスペースを使用するのはなぜですか?

関数型プログラミングのためにいくつかの言語を見てきたので、なぜ一部のfp言語は関数の適用(および定義)に1つ以上の空白文字を使用するのかといつも疑問に思いました。より数学的な方法である。また、後者のスタイルは、括弧なしの場合よりもはるかに明確で読みやすいと思います。

したがって、関数f(xx²)==がある場合、それを呼び出すには2つの選択肢があります。

  • FP:_f x_

    例:

    • ML、Ocaml、F#
    • ハスケル
    • LISP、Scheme(どういうわけか)
  • 非FP:f(x)

    例:

    • ほとんどすべての命令型言語(知っている、コメント/回答を参照)
    • アーラン
    • Scala(単一の引数に対して「演算子表記」も許可)

括弧を「省く」理由は何ですか?

36
pvorb

より数学的な方法のようです

関数型言語は lambda calculus に触発されています。このフィールドでは、括弧は関数の適用には使用されません。

後者のスタイルは、括弧なしの場合よりもはるかに明確で読みやすいと思います。

読みやすさは見る人の目にあります。あなたはそれを読むことに慣れていません。数学演算子に少し似ています。連想性を理解していれば、式の構造を明確にするために数個の括弧が必要です。多くの場合、それらは必要ありません。

カレーもこの規則を使用する良い理由です。 haskellでは、以下を定義できます。

_add :: Int -> Int -> Int
add x y = x + y

x = add 5 6 -- x == 11
f = add 5
y = f 6 -- y == 11
z = ((add 5) 6) -- explicit parentheses; z == 11
_

かっこを使用すると、f(5, 6)(カレーではない)またはf(5)(6)(カレー)という2つの規則を使用できます。 haskell構文は、カレーの概念に慣れるのに役立ちます。カレー以外のバージョンを使用することもできますが、コンビネーターと一緒に使用するのはより困難です。

_add' :: (Int, Int) -> Int
add' (x, y) = x + y
u = add'(5, 6) -- just like other languages
l = [1, 2, 3]
l1 = map (add 5) l -- [6, 7, 8]
l2 = map (\x -> add'(5, x)) l -- like other languages
_

2番目のバージョンでは、xを変数として登録する必要があり、部分式は整数を取り、それに5を加える関数です。カレーバージョンははるかに軽いですが、多くの人がより読みやすいと考えています。

Haskellプログラムは、抽象化を定義および作成する手段として、部分的なアプリケーションとコンビネーターを広範囲に使用するため、これはおもちゃの例ではありません。適切な関数インターフェースは、パラメーターの順序が友好的なカレーの使用法を提供するものです。

別のポイント:パラメータのない関数はf()で呼び出す必要があります。 haskellでは、不変の遅延評価値のみを操作するため、fを記述し、必要に応じていくつかの計算を実行する必要がある値と見なします。その評価には副作用がないので、パラメーターなしの関数とその戻り値に異なる表記をしても意味がありません。

関数適用には他の規約もあります:

  • LISP:(f x)-外部括弧を前に付ける
  • Forth:x f-postfix
59
Simon Bergot

基本的な考え方は、最も重要な操作(関数アプリケーション)を最も読みやすく、最も書きやすくすることです。スペースは読みにくく、入力も非常に簡単です。

これは関数型言語に固有のものではないことに注意してください。 in Smalltalk 、最初のOO言語とそれに触発された言語の1つ( SelfNewspeak 、Objective -C)だけでなく、Ioとそれに触発された言語(Ioke、Seph)では、メソッド呼び出しに空白が使用されます。

Smalltalkスタイル:

anArray sort
anArray add: 2
aString replace: "a" with: "b"

(後者の場合、メソッドの名前はreplace:with:。)

イオスタイル:

anArray sort
anArray add(2)
aString replace("a", "b")

Scalaでは、メソッド呼び出しに空白を使用することもできます。

foo bar(baz)

引数が1つしかない場合は、括弧を省略します。

foo bar baz

Rubyでは、括弧を省略することもできます。

an_array.sort
an_array.add 2
a_string.replace "a", "b"

括弧を使用すると、より数学的な方法のようです

あんまり:

f(x)
sin x
x²
|x|
x!
x + y
xy
½

数学の表記法は、長い間、ひどく矛盾した方法で進化してきました。

関数型言語は、関数アプリケーションが空白を使用して記述されているλ-calculusからインスピレーションを得ています。

25
Jörg W Mittag

関数適用の括弧は、オイラーが私たちに残した多くのサドルの1つにすぎません。他と同じように、何かをする方法がいくつかある場合、数学には慣習が必要です。数学教育が大学の非数学科目にまで及ぶ場合、これらのナンセンスブラケットなしで関数の適用がうまく行われる多くの分野(たとえば、微分幾何学、抽象代数)にあまり慣れていないでしょう。また、インフィックス(ほとんどすべての言語)、ノルムを取るような「アウトフィックス」、または図式(Befunge、代数トポロジー)で適用される関数についても言及しません。

ですから、答えは、広範な数学教育を受けている関数型プログラマーや言語デザイナーの割合がはるかに高いためだと思います。フォン・ノイマンは「若い男、数学では物事が分からない。慣れているだけだ」と言いますが、確かにこれは表記法にも当てはまります。

18
Sean D

Simonの答えには多くの真実がありますが、もっと実用的な理由もあると思います。関数型プログラミングの性質上、関数の連鎖と構成により、命令型プログラミングよりも多くの括弧が生成される傾向があります。これらの連鎖と構成のパターンは、通常、括弧なしで明確に表現することもできます。

肝心なのは、これらの括弧はすべて、読んだり追跡したりするのに面倒です。これがおそらく、LISPがあまり普及していない最大の理由です。したがって、過剰な括弧の煩わしさなしに関数型プログラミングの力を得ることができれば、言語設計者はそのようになる傾向があると思います。結局のところ、言語デザイナーは言語ユーザーでもあります。

もScalaを使用すると、関数スタイルでプログラミングするときにかなり頻繁に発生する特定の状況で、括弧を省略できるため、両方の利点を得ることができます。次に例を示します。

val message = line split "," map (_.toByte)

末尾の括弧は関連性のために必要であり、その他は(ドットと同様に)省略されます。この方法で記述すると、実行する操作の連鎖性が強調されます。命令型プログラマーには馴染みがないかもしれませんが、関数型プログラマーにとっては、この方法で書くのは非常に自然で流動的であり、プログラムに意味を持たない構文を停止して挿入する必要はありませんが、コンパイラーを幸せにするためだけにあります。

9
Karl Bielefeldt

両方の前提が間違っています。

  • これらの関数型言語しないでください関数の適用にスペースを使用します。それらが行うことは、引数として関数の後に続く式を単に解析することです。

    GHCi> f 3
    4
    GHCi> f(3)
    4
    GHCi>(f)3
    4

    もちろん、どちらでもないスペースも括弧も使用すると、式が適切にトークン化されていないために、通常は機能しません

    GHCi> f3

    <‌インタラクティブ>:7:1:
    範囲外:「f3」
    おそらく、「f」を意味している(2行目)

    しかし、これらの言語が1文字の変数名に制限されていれば、それも機能します。

  • また、数学の慣習では通常、関数を適用するために括弧を必要としません。数学者はしばしばsin x –を書くだけでなく、線形関数(通常は線形演算子と呼ばれます)の場合、括弧なしで引数を書くことも非常に一般的です。関数は、引数を直接指定せずに処理されることがよくあります。

だから、本当に、あなたの質問は次のように要約されます:なぜいくつかの言語では関数適用のために括弧が必要なのですか?まあ、どうやらあなたのような一部の人々はこれをもっと読みやすいと考えています。私はこれに強く同意しません。1組のかっこはいいですが、2つ以上のかっこを入れ子にするとすぐに混乱し始めます。 LISPコードはこれを最もよく示しており、どこにでも括弧が必要な場合、ほとんどすべての関数型言語は同様に雑然として見えます。これは命令型言語ではそれほど発生しませんが、主にこれらの言語は、最初は簡潔で明確な1行を記述するほど表現力がないためです。

4
leftaroundabout

小さな歴史的明確化:数学の元の表記は括弧なしでした!

xの任意の関数の表記f xは、ライプニッツ直後の1700年頃にJohan Bernoulliによって導入されました関数について話し始めました(実際にはベルヌーイがϕ xと書きました)。しかし、以前はすでにsinxまたはl x(対数x)のxxの特定の(---)関数の場合、括弧なし。それが今日でも多くの人が罪(x)ではなく罪xと書いている理由だと思います。

ベルヌーイの学生だったオイラーは、ベルヌーイのϕ xを採用し、ギリシャ語をラテン文字に変更してfx。後に彼は、fを「数量」と混同しやすく、f xは製品だったので、f:xを書き始めました。したがって、表記f(x)はオイラーによるものではありません。もちろん、オイラーは、関数型プログラミング言語で括弧が必要なのと同じ理由で括弧が必要でした。たとえば、(fx)+ yf(x + y)。オイラーの後の人々が括弧をデフォルトとして採用したのは、オイラーがf(ax + b)のような複合式を書くのを見たからだと思います。彼はめったにf xと書くことはめったにありません。

これについては、以下を参照してください: オイラーはf(x)を括弧で書きましたか?

関数型プログラミング言語の設計者やラムダ計算の発明者がその表記法の歴史的なルーツを知っていたかどうかはわかりません。個人的には、括弧なしの表記の方が自然だと思います。

2