共分散とデータ型

プログラミングのオプションのトピックは、理解するのに多くの困難を引き起こします.





ラムダのコンテキストで「割り当て」のメタファーを使用して、このトピックを別の角度から説明できることを願っています。





なぜこの分散が必要なのですか?

一般に、変化なしに生活し、平和にプログラムすることができます。これはそれほど重要なトピックではありません。この品質が反映されていないプログラミング言語の例が数多くあります。





共分散は、データ型とコンパイラによるそれらの制御に関するものです。そして、まさにこの場所からロールバックして、データ型とそれが必要な理由について話す必要があります。





タイプへのフラッシュバック

データ型自体もそれほど重要なトピックではありません。たとえば、アセンブラー、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





-  , - ,






-  , . —–





:





  1. N





    • N , : {0, 1, 2, 3, … }





    • N* : {1, 2, 3, … }





  2. Z - (+/-)





  3. Q - ( ), Z





  4. R - ( , e, …)





  5. 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



, :





  1. a b - ,   





  2. a , b - a -  - 





  3. a b, b - () -  -  - .





  4. 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 , , .





- , .





, , .





:





:





  • ( )





    • ( )





      • ( )









  • ( )





    • ( )





      • ( )





, .





- ( ) - .





.





バリエーション は、まず第一に、タスクの対象となるプロパティ/メソッドの存在です。これは、これらのプロパティが存在することを保証するコンパイラ制御メカニズムです。





したがって、たとえば、このまたはそのオブジェクトは、(インタフェースを介して)だけでなく、クラスの下のいくつかの種類であってもよいが、また、実装することができ、私たちに関心のプロパティ/メソッド-これは私が単語の意味するものである 互換性





その後、多重継承、特性、および現代言語のその他の魅力について話すことができますが、これはトピックの範囲を超えています。








All Articles