プログラミングのオプションのトピックは、理解するのに多くの困難を引き起こします.
ラムダのコンテキストで「割り当て」のメタファーを使用して、このトピックを別の角度から説明できることを願っています。
なぜこの分散が必要なのですか?
一般に、変化なしに生活し、平和にプログラムすることができます。これはそれほど重要なトピックではありません。この品質が反映されていないプログラミング言語の例が数多くあります。
共分散は、データ型とコンパイラによるそれらの制御に関するものです。そして、まさにこの場所からロールバックして、データ型とそれが必要な理由について話す必要があります。
タイプへのフラッシュバック
データ型自体もそれほど重要なトピックではありません。たとえば、アセンブラー、brainfuck、REFAL など、データ型が特に必要とされない言語があります。
同じ REFAL またはアセンブラでは、変数のタイプを混同するのは非常に簡単です。たとえば、1 行から別の行を差し引くと仮定するのは非常に簡単です。ただのタイプミスで、悪意はありません。
型付き言語では、コンパイラーはこのタイプミスを認識してプログラムをコンパイルできませんが、...たとえば JS
> 'str-a' - 'str-b'
NaN
JS (JavaScript) このコードを落ち着かせてください。彼らは、これはバグではなく、機能であると教えてくれ ます。
>>> 'str-a' - 'str-b'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for -: 'str' and 'str'
またはジャワ
jshell> "str-a" - "str-b"
| Error:
| bad operand types for binary operator '-'
| first type: java.lang.String
| second type: java.lang.String
| "str-a" - "str-b"
| ^---------------^
, - .
, .
, , , , .
: , Groovy
groovy> def fun1( a, b ){
groovy> return a - b
groovy> }
groovy> println 'fun1( 5, 2 )='+fun1( 5, 2 )
groovy> println "fun1( 'aabc', 'b' )="+fun1( 'aabc', 'b' )
groovy> println 'fun1( [1,2,3,4], [2,3] )='+fun1( [1,2,3,4], [2,3] )
fun1( 5, 2 )=3
fun1( 'aabc', 'b' )=aac
fun1( [1,2,3,4], [2,3] )=[1, 4]
JS
> fun1 = function( a, b ){ return a - b }
[Function: fun1]
> fun1( 5, 2 )
3
> fun1( 'aabc', 'b' )
NaN
> fun1( [1,2,3,4], [2,3] )
NaN
.
, , - , .
/ - .
, .
- .
TypeScript
function sub( x : number, y : number ) {
return x - y;
}
console.log( sub(5,3) )
JS.
function sub( x : number, y : number ) {
return x - y;
}
console.log( sub("aa","bb") )
- :
> tsc ./index.ts
index.ts:5:18 - error TS2345: Argument of type 'string' is not assignable
to parameter of type 'number'.
5 console.log( sub("aa","bb") )
~~~~
Found 1 error.
sub
, , number
.
TypeScript (tsc
).
,
́ — () , .
A — G — A A. f A B G, a ∈ A g ∈ G f(a)=f(g(a)).
, :
- , .
, JS
> fun1 = function( a, b, c ){
... let r = b;
... if( a ) r = c;
... return r + r;
... }
[Function: fun1]
> fun1( 1==1, 2, 3 )
6
> fun1( 1==1, "aa", "b" )
'bb'
> fun1( 1==1, 3, "b" )
'bb'
> fun1( 1!=1, 3, "b" )
6
> fun1( 1!=1, {x:1}, "b" )
'[object Object][object Object]'
r - string number , fun1 , .
r. r .
r :
let r = b
, r , b.
r = c
, r , c.
, .
, :
> fun1 = function( a, b, c ){
... if( typeof(b)!=='number' )throw "argument b not number";
... if( typeof(c)!=='number' )throw "argument c not number";
... let r = b;
... if( a ) r = c;
... return r + r;
... }
[Function: fun1]
> fun1( true, 1, 2 )
4
> fun1( true, 'aa', 3 )
Thrown: 'argument b not number'
, , , .
, +, - … - - ( ), - .
let r = b
r = c
, .
Typescript:
function fun1( a:boolean, b:number, c:number ){
let r = b;
if( a ) r = c;
return r + r;
}
function fun2( a:boolean, b:number, c:string ){
let r = b;
if( a ) r = c;
return r + r;
}
> tsc ./index.ts
index.ts:9:13 - error TS2322: Type 'string' is not assignable to type 'number'.
9 if( a ) r = c;
~
Found 1 error.
, string
number
.
- , .
- , ( ) .
: f(a)=f(g(a))
TypeScript:
function f(a:number) : number {
return a+a;
}
function g(a:number) : number {
return a;
}
console.log( f(1)===f(g(1)) )
- .
- , , ..
function f(a:number) : number {
return a+a;
}
function g(a:number) : number {
return a-1;
}
let r = f(1)
r = f(g(1))
function f(a:number) : number {
return a+a;
}
function g(a:number) : string {
return (a-1) + "";
}
let r = f(1)
r = f(g(1))
( ), :
g string
f number
TypeScript.
, // - , / .
-
- -, TypeScript, - Scala, .
, Solid
- , - ,
- , . —–
:
N
N , : {0, 1, 2, 3, … }
N* : {1, 2, 3, … }
Z - (+/-)
Q - ( ), Z
R - ( , e, …)
C - a+bi, a,b - , i -
:
any -
number -
int -
double - ()
string -
TypeScript
function sum_of_int( a:int, b:int ) : int { return a+b; }
function sum_of_double( a:double, b:double ) : double { return a+b; }
function compare_equals( a:number, b:number ) : boolean { a==b }
let res1 : int = sum_of_int( 1, 2 )
, .. - int, int.
-
let res1 : number = sum_of_int( 1, 2 )
res1 = sum_of_double( 1.2, 2.3 )
res1 - number.
res1 = sum_of_int( 1, 2 ), res1 int, , .. int number number
res1 = sum_of_double( 1.2, 2.3 ) - res1 double ,
? , , .. res1:
let res1 : number = sum_of_int( 1, 2 )
let res2 : number = sum_of_doube( 1.2, 2.3 )
if( compare_equals(res1, res2) ){
...
}
, , , “”
: Box Circle
class Box {
width : number
height : number
constructor( w: number, h: number ){
this.width = w;
this.height = h;
}
}
class Circle {
radius : number
constructor( r: number ){
this.radius = r
}
}
, ,
let boxs : Box[] = [ new Box(1,1), new Box(2,2) ]
let circles : Circle[] = [ new Circle(1), new Circle(2) ]
2 , ,
function areaOfBox( shape:Box ):number { return shape.width * shape.height }
function areaOfCircle( shape:Circle ):number { return shape.radius * shape.radius * Math.PI }
:
boxs.map( areaOfBox ).reduce( (a,b,idx,arr)=>a+b ) +
circles.map( areaOfCircle ).reduce( (a,b,idx,arr)=>a+b )
, / (, ).
, - , , - .
/ - area():number.
interface Shape { area():number }
, Box Circle Shape, areaOfBox, areaOfCircle area.
class Box implements Shape {
width : number
height : number
constructor( w: number, h: number ){
this.width = w;
this.height = h;
}
area():number {
return this.width * this.height
}
}
class Circle implements Shape {
radius : number
constructor( r: number ){
this.radius = r
}
area():number {
return this.radius * this.radius * Math.PI
}
}
,
let shapes : Shape[] = [ new Box(1,1), new Box(2,2), new Circle(1), new Circle(2) ]
shapes.map( s => s.area() ).reduce( (a,b,idx,arr)=>a+b )
, -
Shape, (.. ) (Box, Circle).
, Box Circle Shape.
, ..
let a = b
, :
a b - ,
a , b - a - -
a b, b - () - - - .
a b - - .
, Shape
class Foo {
}
let shapes : Shape[] = [ new Box(1,1), new Box(2,2), new Circle(1), new Circle(2), new Foo() ]
shapes.map( s => s.area() ).reduce( (a,b,idx,arr)=>a+b )
- :
> tsc index.ts
index.ts:31:84 - error TS2741: Property 'area' is missing in type 'Foo' but required in type 'Shape'.
31 let shapes : Shape[] = [ new Box(1,1), new Box(2,2), new Circle(1), new Circle(2), new Foo() ]
~~~~~~~~~
index.ts:2:5
2 area():number
~~~~~~~~~~~~~
'area' is declared here.
Found 1 error.
Foo area, Shape.
SOLID
L - LSP - (Liskov substitution principle): « ». . .
-
-, , , .
, Scala :
package xyz.cofe.sample.inv
object App {
// , String, Boolean, : (String)=>Boolean
def strCmp(a:String):Boolean = a.contains("1")
// , Int, Boolean, : (Int)=>Boolean
def intCmp(a:Int):Boolean = a==1
// , String, Boolean, : (Any)=>Boolean
def anyCmp(a:Any):Boolean = true
def main(args:Array[String]):Unit = {
// Boolean = Boolean
val call1 : Boolean = strCmp("a")
// - Any = Boolean
val call2 : Any = strCmp("b")
// : (String)=>Boolean = (String)=>Boolean
val cmp1 : (String)=>Boolean = App.strCmp;
// - (String)=>Boolean = (Any)=>Boolean
val cmp2 : (String)=>Boolean = App.anyCmp
// : (String)=>Boolean = (String)=>Boolean
val cmp3 : (Any)=>Boolean = App.anyCmp
// !!!!!!!!!!!!!!!!!!!!!!!
//
// - (Any)=>Boolean = (String)=>Boolean
val cmp4 : (Any)=>Boolean = App.strCmp
}
}
Scala:
Any
-
Int, Boolean, String
-Any
,
:
(_,_)=>_
= .
/= .
val
Scala,const
JS
:
// Boolean = Boolean
val call1 : Boolean = strCmp("a")
// : (String)=>Boolean = (String)=>Boolean
val cmp1 : (String)=>Boolean = App.strCmp;
cmp1 - , , :
(String)=>Boolean (String)=>Boolean
-
// - Any = Boolean
val call2 : Any = strCmp("b")
// - (String)=>Boolean = (Any)=>Boolean
val cmp2 : (String)=>Boolean = App.anyCmp
call2, , cmp2.
(String) => Boolean (Any) => Boolean
String -> -> Any - -.
, WTF? - !
// , String, Boolean, : (String)=>Boolean
def strCmp(a:String):Boolean = a.contains("1")
// , String, Boolean, : (Any)=>Boolean
def anyCmp(a:Any):Boolean = true
cmp2( "abc" )
"abc"
anyCmp(a:Any)
, String Any, .
anyCmp( "string" )
anyCmp( 1 )
, anyCmp( true )
- ,
,
()
.. , - , -.
:
-
assign a <- b
- -
call a -> b
, :
-,
-,
Scala, TypeScript
TypeScript 4.2.4 - /
interface Shape {
area():number
}
class Box implements Shape {
width : number
height : number
constructor( w: number, h: number ){
this.width = w;
this.height = h;
}
area():number {
return this.width * this.height
}
}
class Circle implements Shape {
radius : number
constructor( r: number ){
this.radius = r
}
area():number {
return this.radius * this.radius * Math.PI
}
}
class Foo {
}
const f1 : (number)=> boolean = a => true;
const f2 : (object)=> boolean = a => typeof(a)=='function';
const f3 : (any)=>boolean = f1;
const f4 : (number)=>boolean = f3;
const _f1 : (Box)=>boolean = a => true
const _f2 : (any)=>boolean = _f1
const _f3 : (Shape)=>boolean = _f1
const f3 : (any)=>boolean = f1;
const _f3 : (Shape)=>boolean = _f1
( ) ,
user@user-Modern-14-A10RB:03:14:17:~/code/blog/itdocs/code-skill/types: > ./node_modules/.bin/tsc -version Version 4.2.4 user@user-Modern-14-A10RB:03:16:53:~/code/blog/itdocs/code-skill/types: > ./node_modules/.bin/tsc --strictFunctionTypes index.ts user@user-Modern-14-A10RB:03:18:26:~/code/blog/itdocs/code-skill/types: > ./node_modules/.bin/tsc --alwaysStrict index.ts user@user-Modern-14-A10RB:03:19:04:~/code/blog/itdocs/code-skill/types:
, .
-/-
.
!
, , .
- - , .
- - .
C , JS , , .
- , .
, , .
:
:
( )
( )
( )
( )
( )
( )
, .
- ( ) - .
.
バリエーション は、まず第一に、タスクの対象となるプロパティ/メソッドの存在です。これは、これらのプロパティが存在することを保証するコンパイラ制御メカニズムです。
したがって、たとえば、このまたはそのオブジェクトは、(インタフェースを介して)だけでなく、クラスの下のいくつかの種類であってもよいが、また、実装することができ、私たちに関心のプロパティ/メソッド-これは私が単語の意味するものである 互換性。
その後、多重継承、特性、および現代言語のその他の魅力について話すことができますが、これはトピックの範囲を超えています。