それは少し主観的ですが、どの要因がオペレーターを使いやすくするのか、鈍くて難しくするのかをより明確に理解したいと思っています。私は最近、言語の設計を検討してきましたが、私が常に振り返る問題の1つは、言語の重要な操作をいつ演算子にするか、キーワードや関数をいつ使用するかです。
Haskellは、カスタムオペレーターの作成が簡単であり、多くの場合、新しいデータ型が複数のオペレーターで使用できるようにパッケージ化されるため、これについてはやや悪名高いです。たとえば、Parsecライブラリには、パーサーを結合するための多数の演算子が付属して>.
おり、.>
今のような宝石を覚えていますが、今の意味を思い出すことさえできませんが、彼らは実際に意味します。などの関数呼び出しleftCompose(parser1, parser2)
は改善されましたか?確かにより冗長ですが、いくつかの点で明確です。
Cライクな言語での演算子のオーバーロードも同様の問題ですが、おなじみの演算子のよう+
な意味を通常とは異なる新しい意味でオーバーロードするという追加の問題によって混同されます。
新しい言語では、これはかなり難しい問題のように思えます。たとえば、F#では、キャストはC#スタイルのキャスト構文または冗長VBスタイルの代わりに、数学的に導出された型キャスト演算子を使用します。C#:(int32) x
VB:CType(x, int32)
F#:x :> int32
理論的には、新しい言語にはほとんどの組み込み機能の演算子があります。変数宣言の代わりにdef
、dec
またはvar
変数宣言のために、なぜそうでない! name
か、@ name
または類似した何か。それは確かに、宣言に続くバインディングを短縮します。@x := 5
代わりに、declare x = 5
またはlet x = 5
ほとんどのコードは多くの変数定義を必要とするでしょう。
オペレーターが明確で有用なのはいつですか?
+
、文字列の連結または<<
ストリーム)。一方、Haskellでは、演算子はカスタム名(つまり、オーバーロードされていない)を持つ関数か、型クラスの一部のいずれかです。つまり、ポリモーフィックではあるが、すべての型に対して同じ論理的なことを行います。同じ型の署名もあります。だから、>>
ある>>
種類ごとに、ビットシフトになるだろうことはありません。