関数に渡される引数の量を制限することに基づく言語


16

このアイデアは、+、-、%などのファクト演算子に触発されており、1つまたは2つの引数が渡され、副作用がない関数と見なすことができます。私または他の誰かが、3つ以上の引数の受け渡しを停止し、戻り値を介してのみ機能する言語を作成すると仮定します。

a)そのような言語はコードを理解しやすくするでしょうか?

b)コードの流れはより明確になりますか?(より多くのステップを強制し、潜在的に少ない対話を「非表示」にします

c)制限により、より複雑なプログラムでは言語が非常に大きくなりますか?

d)(ボーナス)賛否両論に関するその他のコメント

注意:

2つの決定を行う必要があります。1つ目は、main()または同等の外部でのユーザー入力を許可するかどうか、および配列/構造体を渡すときに何が起こるかについてのルールです。たとえば、1つの関数で複数の値を追加したい場合、その関数を配列にまとめることで制限を回避できます。これは、配列または構造体がそれ自体と対話することを許可しないことで停止できます。これにより、たとえば、各数値をその位置に応じて異なる量で除算できます。


4
こんにちは。長所と短所のリストは、悪い答えをする傾向があります。質問を言い換えて、必要な情報を別の形式で取得する方法はありますか?
メタファイト

22
あなたの推論は私にとっても意味をなさない。一部の関数には引数がほとんどないため、すべての関数を制限しましょうか?通常、任意の制限を提案する場合、理由があります。これで何が得られるのかわかりません。

2
「what if」の質問には本質的に問題があるわけではありません(@MetaFightが言ったように答えるのが難しい場合もあります)が、もしあなたがそのことを考え、質問をするのに十分な気遣いさえすれば、利点は、「何?いいえ!どうしてそんなことをするのが馬鹿げている」という私の最初の反応が正確であると確信しています。

6
関数ごとに1つの引数のみを許可する言語がかなりあります。ラムダ計算に基づいたものです。結果は通常、単一のリスト引数を取る関数、またはすべての引数が処理されるまで次の引数を取る関数を返す関数ですresult = f(a)(b)…(z)。これはHaskellなどのML言語ファミリーの場合ですが、概念的にはLisp、JavaScript、Perlなどの他の言語でも同様です。
アモン

3
@Orangesandlemons:それでは、乗算と加算(エンコード用)および除算と減算(デコード用)だけを使用して、1つの整数内の任意の数の整数をエンコードできます。そのため、整数、または少なくとも乗算、加算、除算、減算を禁止する必要があります。(プログラミングの力の結果の1つは、ほとんどすべてを使用してほとんどすべてをエンコードできることです。したがって、制限は本当に非常に困難です。一般に、制限は実際には何も「制限」せず、プログラマを困らせます。)
Jörg Wミットタグ

回答:


40

Robert C. Martinの著書「Clean Code」では、最大で0、1、または2つのパラメーターを持つ関数の使用を強く推奨しているため、少なくともこのスタイルを使用するとコードがきれいになると考える経験豊富な著者が1人います(ただし、確かにここでは究極の権威ではなく、彼の意見は議論の余地がある)。

ボブ・マーティンが私見的に正しいのは、3つ以上のパラメータを持つ関数は、多くの場合、コードの匂いの指標です。多くの場合、パラメーターはグループ化されて結合されたデータ型を形成する場合があります。他の場合は、関数が単純に多すぎることを示すインジケーターになる場合があります。

ただし、このための新しい言語を発明することは良い考えではないと思います。

  • コード全体にこのようなルールを強制する場合は、既存の言語のコード分析ツールが必要です。このために完全に新しい言語を発明する必要はありません(たとえば、C#の場合は「fxcop」などを使用できます) )。

  • パラメータを新しいタイプに結合するのは面倒なだけの価値がないように見える場合もあれば、純粋な人工的な組み合わせになる場合もあります。たとえば、.NetフレームワークのこのFile.Openメソッドを参照してください。4つのパラメーターが必要です。異なるAPIを関数に提供する最も実用的な方法だと考えたため、そのAPIの設計者は意図的にこれを行ったと確信しています。

  • 技術的な理由で2つ以上のパラメーターで物事を簡単にする現実のシナリオがあります(たとえば、単純なデータ型の使用に縛られ、異なる組み合わせができない既存のAPIへの1:1マッピングが必要な場合)パラメーターを1つのカスタムオブジェクトに)


16
複数のパラメータを持つ匂いは、多くの場合、実際には異なるパラメータが一緒に属します。たとえば、ボディマス指数、BMIの計算を考えてみましょう。それは、人の長さと体重の関数です。f(長さ、体重)、しかし、これらの2つのパラメータは本当に一緒に属します。なぜなら、ある人の身長と別の人の体重でこの計算を行うでしょうか?したがって、それをより適切に表すには、f(person)を取得します。ここで、人は体重と長さのインターフェースを持つことができます。
ピーターB

@PieterB:もちろん、私の編集を参照してください。
ドックブラウン

5
小さな、小さな言語nitpick:「コードのにおいを示している可能性があります」の定義によって、あなたは最終的にコードを変更しない場合でも、何かを再考する必要があることだけ表示コードのにおいはありませんか?したがって、コードの匂いは「表示されません」。特定の側面が問題の可能性を示している場合、それコード臭です。番号?
jpmc26

6
@ jpmc26:別の観点から、コードのにおいは問題の兆候ではなく、可能性のある問題です;-)それはすべてコードのにおいの正確な定義に依存します?)
hoffmale

3
@PieterB誰か実際にこれをしますか?2つの任意の値でBMIを計算するたびに、新しいPersonインスタンスを作成する必要があります。もちろん、アプリケーションが既にPersonsを使用して開始していて、f(person.length、person.height)のような処理を頻繁に実行している場合、それを少しクリーンアップできますが、グループパラメーター専用の新しいオブジェクトを作成するのはやり過ぎのようです。
弁護士

47

Haskellなど、すでにこの方法で機能する言語がたくさんあります。Haskellでは、すべての関数は1つの引数を取り、1つの値を返します。

n個の引数を取る関数を、n-1個の引数を取る関数に置き換えて、最終的な引数を取る関数を返すことは常に可能です。これを再帰的に適用すると、任意の数の引数を取る関数を常に1つの引数を取る関数で置き換えることが常に可能です。そして、この変換はアルゴリズムによって機械的に実行できます。

これは、1950年代に広範囲に研究したHaskell Curry、1924年にそれを記述したMosesSchönfinkel、および1893年に予言したGottlob Fregeにちなんで、Frege-Schönfinkeling、Schönfinkeling、Schönfinkel-Currying、またはCurryingと呼ばれます。

つまり、引数の数を制限しても、影響はまったくありません。


2
もちろん、関数を返すことを許可する場合です。そうでなくても、あなたがしなければならないのは、メインプログラムで呼び出される次の関数を持っていることです。つまり、最初の追加が追加を追加するための関数を返す関数であるか、単純に2回呼び出すことができる1 + 1 + 1を使用できます。後者のスタイルは、理論的にはよりクリーンなのでしょうか、それとも間違っていますか?

5
「影響はまったくありません」-OPの質問は、コードの可読性が増減するかどうかであり、言語のそのような設計上の決定がそれに影響を及ぼさないとは思わないでしょうか。
ドックブラウン

3
@DocBrown適切なパワーと演算子のオーバーロードにより、カレー言語を使用して、カリー化されていない言語のように見せることができます。例:f *(call_with: a,b,c,d,e) オーバーロードcall_with :して、チェーンを開始し、チェーン,を拡張*し、LHSで呼び出しfて、チェーンの各コンテンツを一度に1つずつ渡します。十分に弱いオペレーター過負荷システムは、構文を煩わしくするだけですが、それは何よりもオペレーター過負荷システムの障害です。
ヤック

実際、Haskellのカリー化は、n個の引数を持つ関数を、1つの引数を持つ関数に還元し、n-1個の引数を持つ別の関数を返します。
ライアンライヒ

2
@RyanReichあなたは、その型シグニチャーでHaskell関数の「引数の数」の「ゴースト」を見ることができると思います。一般に、署名の最後の型変数関数型であるかどうかを知る方法がないため、真の署名ではなくゴーストです。とにかく、このゴーストが存在しても、Haskellではすべての関数が1つの引数を取り、非関数値または1つの引数を受け取る別の関数を返すという事実を無効にしません。これは->の結合性に組み込まれています:a-> b-> cはa->(b-> c)です。あなたはここでほとんど間違っています。
イアン

7

私はここ数週間、Jコンピューター言語を学ぼうと試みてきました。Jでは、ほとんどすべてが演算子であるため、「monads」(引数が1つだけの関数)と「dyads」(引数が2つだけの関数)しか取得できません。さらに引数が必要な場合は、配列で提供するか、「ボックス」で提供する必要があります。

Jは非常に簡潔ですが、前身のAPLと同様に、非常に不可解な場合もあります。文字ではなく名前を使用して演算子を作成することにより、Jプログラムをより読みやすくすることができます。


ああ、それは配列が自分自身とやり取りできるようにします。

5

開発者を制約する方法に基づいた言語は、言語開発者が各プログラマーのニーズを理解するという前提に依存しています。これが実際に有効な場合があります。たとえば、ミューテックスとセマフォを使用した同期を必要とするマルチスレッドプログラミングの制約は、多くのプログラマが「良い」と見なします。同様に、マルチスレッドガベージコレクションアルゴリズムのニュアンスを完全に把握したい人はほとんどいません。GCアルゴリズムを単純に破らない言語は、プログラマにあまりにも多くのニュアンスを認識させるよりも優先されます。

言語開発者として、あなたがあなたの言語を使用するプログラマよりもはるかによく引数を渡すことを理解しているので、あなたが有害だと思うことを彼らが防ぐのに価値がある理由について、有効な議論をする必要があります。それは難しい議論になると思います。

また、プログラマー制約を回避することを知っておく必要があります。3つ以上の引数が必要な場合、カリー化などの手法を使用して、引数の少ない呼び出しに変換します。ただし、多くの場合、これを改善するのではなく、読みやすさが犠牲になります。

私がこの種のルールで知っている言語のほとんどはエソランであり、限られた機能セットで実際に操作できることを実証するために設計された言語です。特に、すべての文字がオペコードであるエソランは、単にオペコードのリストを短くする必要があるため、引数の数を制限する傾向があります。


これが最良の答えです。
ジャレッドスミス

1

次の2つが必要です。

  • 閉鎖
  • 複合データ型

JörgW Mittagによって書かれた答えを説明する数学的な例を追加します。

ガウス関数を考えます

ガウス関数には、その形状に2つのパラメーター、つまり平均(曲線の中心位置)と分散(曲線のパルス幅に関連)があります。2つのパラメーターに加えて、1つはx評価するために自由変数の値を提供する必要があります。

最初のステップでは、3つのパラメーター、つまり平均、分散、自由変数すべてをとるガウス関数を設計します。

2番目のステップでは、平均と分散を1つのものに結合する複合データ型を作成します。

3番目のステップでは、2番目のステップで作成した複合データ型にバインドされたガウス関数のクロージャーを作成することにより、ガウス関数のパラメーター化を作成します。

最後に、3番目のステップで作成されたクロージャーを、自由変数の値を渡して評価しますx

したがって、構造は次のとおりです。

  • 評価(計算)
    • ParameterizedGaussian(閉包:数式、およびいくつかのバインドされた変数)
      • GaussianParameters(複合データ型)
        • 平均(値)
        • 分散(値)
    • X(自由変数の値)

1
  1. ほぼすべてのプログラミング言語で、何らかのタイプのリスト、配列、タプル、レコード、またはオブジェクトを唯一の引数として渡すことができます。唯一の目的は、他のアイテムを個別に関数に渡すのではなく保持することです。一部のJava IDE には、まさにそれを行うための「パラメーターオブジェクトの抽出」機能さえあります。内部的に、Javaは配列を作成して渡すことにより、可変数の引数を実装します。

  2. あなたが本当に純粋な形で話していることをしたいのであれば、ラムダ計算を見る必要があります。それはまさにあなたが説明するものです。Webで検索できますが、私にとって意味のある説明はTypes and Programming Languagesにありました

  3. HaskellおよびMLプログラミング言語を見てください(MLの方が簡単です)。どちらもラムダ計算に基づいており、概念的には関数ごとに1つのパラメーターしかありません(少し目を細めている場合)。

  4. Josh BlochのItem 2は、「多くのコンストラクターパラメーターに直面したときにビルダーを検討する」です。これがどのように冗長になるかを見ることができます、このように書かれたAPIを使用するのは楽しいことです。

  5. 一部の言語には、名前付きのパラメーターがあります。これは、巨大なメソッドシグネチャをナビゲートしやすくする別のアプローチです。 Kotlinは、たとえば名前付き引数持っています。

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