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


34

関数型プログラミングのためにいくつかの言語を見てきましたが、なぜ一部のfp言語は関数アプリケーション(および定義)に1つ以上の空白文字を使用するのかと疑問に思いましたが、ほとんどの(すべて?)命令型/オブジェクト指向言語は括弧を使用していますより数学的な方法である。また、後者のスタイルは、括弧がない場合よりもはるかに明確で読みやすいと思います。

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

  • FP: f x

    例:

    • ML、Ocaml、F#
    • ハスケル
    • LISP、Scheme(なんとか)
  • 非FP: f(x)

    例:

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

括弧を「除外」する理由は何ですか?


9
それをもっと混乱させるために、私は簡潔を意味しました。
デン14

11
あなたはHaskellのを学ぶ場合@Den、構文は、少なくとも混乱のものの一つになります:P
サイモンBergot

5
かっこを使用する方が数学的になり、例として指数関数を使用するという皮肉を覚えていますか?
ヨルグW

12
@Denあなたは、その構文のために言語を拒否することによって自分自身に害を及ぼしています。xmlやsqlの学習に問題はありませんでした(これらは汎用言語ではありませんが、独自の構文を定義しています)。
サイモンベルゴ14

7
シェルスクリプト(bashなど)は通常、コマンドを呼び出すためにパラメーターを使用しないことを指摘したいと思います。PowerShellには、両方の世界で最悪の機能があります。関数はかっこで宣言され、かっこなしで呼び出されます。
クリスハーパー

回答:


59

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

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

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

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

カリー化もこの規則を使用する正当な理由です。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

かっこでは、2つの規則を使用できます:(f(5, 6)カレーではない)またはf(5)(6)(カレー)。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プログラムは、抽象化を定義および構成する手段として、部分アプリケーションとコンビネータを広範囲に使用しているため、これはおもちゃの例ではありません。優れた関数インターフェースは、パラメーターの順序がわかりやすいカリー化された使用法を提供するインターフェースです。

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

関数の適用には他の規則もあります。

  • Lisp:(fx)-外部括弧付きのプレフィックス
  • Forth:xf-後置

7
マイナーピック:用語は、「カリー化」および「カリード」ではなく、「カリー化」および「カレー」です。
ドーバル14

「非カリー化」haskellの非カリー化関数とは何ですか?
ベン14

3
@ user1737909タプルを引数として取る関数。
ドーバル14

1
@Doval実際には、「schönfinkeling」と「schönfinkeled」である必要があります。しかし、まあ、歴史は常に勝者を遡及的に定義します。
Profpatsch

括弧で囲まれたカリー化構文を考えると、デフォルトではf(a, ,b)add(a, )またはのadd(, b)ような柔軟性があります。
フレネル

25

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

これは機能言語に固有のものではないことに注意してください、例えばSmalltalkでは、最初のオブジェクト指向言語の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
½

数学表記は、恐ろしく矛盾した方法で長い時間をかけて進化してきました。

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


3
編集の経済性についても議論があります。特に、関数型言語は通常、構成を直接サポートします。引数の代わりに関数を括弧で囲むのは理にかなっています。「1回」行うだけで済みます:e(f(g(x)))ではなく(e。f。g)x。また、少なくともHaskellは、f xではなくf(x)を実行することを止めません。ただの慣用句ではありません。
ノーメン14

18

関数アプリケーションの括弧は、オイラーが残した多くのサドルの1つにすぎません。他の何かと同じように、何かをするいくつかの方法があるとき、数学は規則を必要とします。あなたの数学教育が大学で数学以外の科目にまで及ぶ場合、おそらくこれらのナンセンスな括弧なしで関数適用が楽しく行われる多くの分野(微分幾何学、抽象代数など)に精通していないでしょう。また、中置詞(ほとんどすべての言語)が適用されている関数、ノルムを取るような「前置詞」、図式的(Befunge、代数的トポロジー)についても言及していません。

答えとしては、機能的なプログラマーと言語デザイナーの大部分が数学的教育を受けているためだと思います。フォン・ノイマンは「若い男、数学では物事を理解していない。あなたはそれらに慣れるだけだ」と言っているが、これは確かに記法について正しい。


7
でも私は、上で開始されませんf(x)sin x|x|x!x + yxy½対A合計対不可欠な対...
イェルクWミッターク

2
フォンノイマンの引用の場合は+1。残りの答えは+1ですが、+ 2はできません。:(
pvorb 14

2
ここでエリート主義のヒントをキャッチします。「関数型プログラミング言語の設計者は教育を受けやすい」という中立性に異議を唱えます。
キャプテンコードマン14

7
@CaptainCodeman彼は数学の教育を受けていると言いますが、私はそれに同意します。少なくともHaskellに関しては、両方の概念が本質的に数学的であり、コミュニティも数学的に傾いていることに気付くことができます。彼らはより知的ではなく、数学の教育を受けているだけです。
ポール14

5
@CaptainCodemanいいえ、彼は一般的に彼らがより多くの教育を受けていることを暗示しておらず、数学の教育を受けているだけです。それがまさに彼が言ったことである:「広範な数学教育」。:)
ポール14

8

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

一番下の行は、それらのすべての括弧は、読み取りと追跡が面倒です。これはおそらく、LISPの人気が一番低い理由の1つです。したがって、過剰な括弧を煩わせることなく関数型プログラミングの力を得ることができれば、言語設計者はそのようになる傾向があると思います。結局のところ、言語デザイナーは言語ユーザーでもあります。

Scalaでも、プログラマーは特定の状況で括弧を省略することができます。括弧は、機能的なスタイルでプログラミングするときに頻繁に発生するため、両方の長所を最大限に活用できます。例えば:

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

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


2
「一番下の行は、これらのすべての括弧が読み、追跡するのが面倒です。おそらく、LISPが人気がない理由の1つです。」:括弧はLispが人気でない理由だとは思わない:思わないそれらは特に読みにくく、他の言語にははるかに厄介な構文があります。
ジョルジオ14

2
LISP構文は、非常に高度な直交性を備えた迷惑な括弧をほぼ補います。それは単に、それがまだ使用できるようにする他の償還機能を持っていることを意味します。かっこが迷惑ではないということではありません。誰もがそのように感じているわけではないことを理解していますが、私が出会った大多数のプログラマーがそうしていると思います。
カールビーレフェルト14

「Lost In Stupid Parentheses」は私のお気に入りのLISPの略語です。Wispなどの言語のように、コンピューターは人道的な方法を使用してコードブロックを指定し、冗長性を削除することもできます。
シーズティマーマン

4

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

  • これらの関数型言語、関数の適用にスペースを使用しません。それらが行うことは、引数として関数の後に来る式を単純に解析することです。

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

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

    GHCi> f3

    <‌interactive>:7:1:
        スコープ外: 'f3'
        おそらく 'f'を意味した(2行目)

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

  • また、数学の規則では、通常、関数の適用に括弧は必要ありません。だけでなく、意志の数学者が多い書き込み罪X -線形関数(通常はその後、オペレータリニアと呼ばれる)、それが機能リニア(多くの関数型プログラミングで任意の関数のように)頻繁に直接供給することなく、処理されるかもしれないので、括弧なしの引数を記述することも非常に多く、通常だため引数。

本当に、あなたの質問は次のように要約されます:なぜいくつかの言語では関数の適用に括弧が必要なのですか さて、あなたのような一部の人々は、これをより読みやすいと考えています。私はこれに強く反対します:ペアのペアは素晴らしいですが、ネストされたペアのうちの2つが増えるとすぐに混乱し始めます。Lispコードはこれを最もよく示しており、どこでも括弧が必要な場合、ほとんどすべての関数型言語が同様に散らかって見えます。これは命令型言語ではそれほど起こりませんが、主にこれらの言語は簡潔で明確なワンライナーを書くには十分に表現力がないためです。


わかりました、質問は完璧ではありません。:)したがって、描画する結論は、「括弧はスケーリングしません。」です。
pvorb

2
NOR非機能言語です括弧を必要とするで全会一致で。いくつかの例では、Smalltalk has 、Objective C has 、RubyとPerlの両方で、関数呼び出しとメソッド呼び出しで括弧を省略できます。object method: args[object method: args]
ホッブズ14

1

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

xの任意の関数の記法fxは、ライプニッツが関数の話を始めた直後に1700年頃にJohan Bernoulliによって導入されました(実際、Bernoulliはϕ xを書きました)。しかし、その前に、括弧のないxの特定の関数に対してsin xlxxの対数)のような表記法をすでに使用している多くの人々。それが今日の多くの人々がsin (x)の代わりにsin xを書く理由だと思う。

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

これについては、オイラーはf(x)を括弧で書いたことがありますか?

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.