c# 動的型付け 型推論 - 弱く型付けされた言語に関する明らかな矛盾についての明確化を求める





4 Answers

他者が指摘しているように、「強く型付けされた」および「弱く型付けされた」という用語は、あなたの質問に対する答えが一つもないほど多くの異なる意味を持っています。 しかし、Perlがあなたの質問に具体的に言及して以来、私はPerlがどのような意味で弱く型付けされているのかを説明しようとします。

要点は、Perlでは、「整数変数」、「float変数」、「文字列変数」、「ブール変数」などは存在しないということです。 実際、ユーザーが(通常)伝えることができる限り、整数、浮動小数点数、文字列またはブールもありません。あなたが持っているのはすべて「スカラー」です。これらはすべて同時にこれらのものです。 例えば、次のように書くことができます:

$foo = "123" + "456";           # $foo = 579
$bar = substr($foo, 2, 1);      # $bar = 9
$bar .= " lives";               # $bar = "9 lives"
$foo -= $bar;                   # $foo = 579 - 9 = 570

もちろん、あなたが正しく注記しているように、これはすべてタイプ強制とみなすことができます。 しかし、ポイントは、Perlでは、型は常に強制されるということです。 実際には、変数の内部 "タイプ"が何であるかをユーザが知ることは非常に難しいです:上記の例の2行目で、 $barの値が文字列"9"か数字9がかわいいかを尋ねる多くの意味がない。なぜなら、Perlが関係する限り、 それらは同じことだからである 。 確かに、Perlスカラーが内部的に文字列と数値の両方を同時に持つことさえ可能です。例えば、上記の2行目以降の$fooの場合です。

これは、Perl変数が型なし(つまり、内部型をユーザーに公開しないため)であるため、演算子をさまざまな型の引数に対して異なる処理をするためにオーバーロードすることはできません。 演算子は、その引数がどのような値であるかを伝えることができないため、「この演算子は数字のためにXを、文字列のためにYを」と言うことはできません。

たとえば、Perlは数値加算演算子( + )と文字列連結演算子( . )の両方を必要とします:上で見たように、文字列( "1" + "2" == "3" )または数字を連結する( 1 . 2 == 12 )。 同様に、数値比較演算子==!=<><=>=および<=>は引数の数値を比較し、文字列比較演算子eqneltgtlegeおよびcmpはそれらを辞書的に文字列として比較します。 したがって、 2 < 10 2 gt 10 (ただし、 "02" lt 10"02" == 2 )。 (JavaScriptのような他の言語では、Perlのような微妙な型指定に対処すると同時にオペレータのオーバーロードが発生することに注意してください。これは+の連想性の喪失のような醜さにつながります)。

(ここでの軟膏のフライは、歴史的な理由から、Perl 5にはビット単位の論理演算子のようないくつかのコーナーケースがあり、その振る舞いは引数の内部表現に依存していることが一般的です。驚くべき理由で内部表現が変わる可能性があるため、特定の状況でオペレータが何をするかを予測するのは難しい場合があります)。

言われたすべては、Perl 強力な型を持っていると主張することができます。 あなたが期待している種類のものではありません。 具体的には、前述の「スカラー型」に加えて、「配列」と「ハッシュ」の2つの構造化型もあります。 それらはスカラーとは非常に異なっており、Perl変数の型が異なることを示しています(スカラの場合は$ 、配列の場合は@ 、ハッシュの場合は% )。 これらの型の間に強制規則があるので、例えば%foo = @barと書くことができます 、それらの多くはかなり損失があります:例えば、 $foo = @barは、配列@bar 長さを内容ではなく$fooに割り当てます。 (また、タイプグロブやI / Oハンドルのように、よく見かけることのない奇妙なタイプがいくつかあります。)

また、この素晴らしいデザインのちょっとした欠点は、特別な種類のスカラーである参照型が存在することです(また、 ref演算子を使用して通常のスカラーと区別できます)。 参照を通常のスカラとして使用することは可能ですが、文字列/数値は特に有用ではありません。通常のスカラ操作を使用して参照を変更すると、特殊な参照参照が失われがちです。 また、Perl変数2はクラスにブレスされ、そのクラスのオブジェクトに変換されます。 PerlのOOクラスシステムは、前述のプリミティブ型(または型なし)システムとやや直交していますが、 ダック型のパラダイムに従うという意味では「弱」です。 一般的な見解は、Perlでオブジェクトのクラスをチェックしていると、何か間違っているということです。

1実際には、sigilはアクセスされる値の型を表します。たとえば、配列@foo最初のスカラーは$foo[0]ます。 詳細はperlfaq4を参照してください。

2 Perlのオブジェクトは、(通常は)それらの参照によってアクセスされますが、実際にはblessは、参照が指し示す(おそらく匿名の)変数です。 しかし、実際の祝福された変数を別のものに割り当てると、祝福​​はそれほど浅く、祝福されていないコピーになります。 詳細はperlobjを参照してください。

強い型付け 静的型付け言語 一覧

私は強いタイピングを理解していると思いますが 、弱いタイピングの例を探すたびに、タイプを自動的に強制/変換するプログラミング言語の例を見つけることになります。

たとえば、「 Typing:Strong vs. Weak 」というこの記事では、静的対動的の場合、次のようにすると例外が発生するため、Pythonが強く型付けされていると報告しています。

Python

1 + "1"
Traceback (most recent call last):
File "", line 1, in ? 
TypeError: unsupported operand type(s) for +: 'int' and 'str'

しかし、そのようなことはJavaとC#で可能であり、私たちはそれらを弱く型付けしたとは考えていません。

Java

  int a = 10;
  String b = "b";
  String result = a + b;
  System.out.println(result);

C#

int a = 10;
string b = "b";
string c = a + b;
Console.WriteLine(c);

Weakly Type Languagesという別の記事では、明示的な変換をせずに文字列を数字と逆順に連結できるため、Perlは弱く型付けされていると言われています。

Perl

$a=10;
$b="a";
$c=$a.$b;
print $c; #10a

だから同じ例では、Perlは弱く型付けされていますが、JavaやC#は作成されません。

さあ、これは混乱している

著者は、異なるタイプの値に対する特定の演算の適用を妨げる言語が強く型付けされ、逆に弱い型付けが行われることを意味するように思われる。

したがって、いくつかの点では、ある言語が多くの自動変換やタイプ間強制(perlのように)が弱い型指定とみなされる可能性がありますが、わずかな変換しか提供しない他の言語は終了する可能性がある強く型付けされていると考えられる

私はこのinterepretationで間違っている必要がありますが、私は信じる傾向がある、私はちょうどそれを説明する理由や方法を知らない。

ですから、私の質問は次のとおりです:

  • 本当に弱く型付けされた言語が本当に意味することは何ですか?
  • 言語による自動変換/自動強制変換に関係しない、弱い型の良い例を挙げてください。
  • 言語を弱く型付けして強く型付けすることはできますか?



完璧な例はWikipediaから来ます:

一般的に、強いタイピングは、プログラミング言語が起こることが許される混合に重大な制限を課すことを意味する。

弱いタイピング

a = 2
b = "2"

concatenate(a, b) # returns "22"
add(a, b) # returns 4

強いタイピング

a = 2
b = "2"

concatenate(a, b) # Type Error
add(a, b) # Type Error
concatenate(str(a), b) #Returns "22"
add(a, int(b)) # Returns 4

弱いタイピング言語は、エラーなしで異なるタイプを混在させることができます。 強力な型言語では、入力型を予期した型にする必要があります。 強い型の言語では、型は変換され( str(a)は整数を文字列に変換する)、またはキャスト( int(b) )することができます。

これはすべてタイピングの解釈に依存します。




弱い型付けは実際には、型の高いパーセンテージが暗黙的に強制され、コーダが意図したものを推測しようとしていることを意味します。

厳密な型定義とは、型が強制されないか、少なくとも型どりが少ないことを意味します。

静的型定義は、変数の型がコンパイル時に決定されることを意味します。

多くの人々は最近、「明示的に型指定された」と「強く型付けされた」型を混同しています。 「マニフェスト型」とは、変数の型を明示的に宣言することを意味します。

Pythonは大部分が強く型付けされていますが、ブール値のコンテキストではほとんど何でも使用できますが、ブール値は整数コンテキストで使用でき、整数は浮動小数点コンテキストで使用できます。 あなたの型を宣言する必要はないので、明らかに型付けされていません(Cythonは例外ではありませんが、完全にはPythonではありません)。 また、静的に型指定されていません。

型を宣言したり、型をコンパイル時に決定したり、整数とポインタ、整数と倍精度を混在させたり、ある種の型へのポインタをキャストすることができるため、CやC ++は明示的に型指定され、静的に型付けされています。別の型へのポインタ。

Haskellは明らかにタイプされていないので興味深い例ですが、静的で強く型付けされています。




@Eric Lippertの答えが気に入っていますが、強く型付けされた言語は、通常、プログラムの各ポイントでの変数の種類を明示的に知っています。弱く型付けされた言語はそうではないので、特定の型に対しては不可能な操作を実行しようとする可能性があります。これを見る最も簡単な方法は関数にあると考えています。C ++:

void func(string a) {...}

変数aは文字列型であることが知られており、互換性のない操作はコンパイル時に捕捉されます。

Python:

def func(a)
  ...

変数aは何でもかまいません。実行時に捕捉される無効なメソッドを呼び出すコードを持つことができます。




Related