What is dependent typing?

后端 未结 4 1001
隐瞒了意图╮
隐瞒了意图╮ 2020-12-22 17:51

Can someone explain dependent typing to me? I have little experience in Haskell, Cayenne, Epigram, or other functional languages, so the simpler of terms you can use, the m

4条回答
  •  别那么骄傲
    2020-12-22 18:16

    Dependent types enable larger set of logic errors to be eliminated at compile time. To illustrate this consider the following specification on function f:

    Function f must take only even integers as input.

    Without dependent types you might do something like this:

    def f(n: Integer) := {
      if  n mod 2 != 0 then 
        throw RuntimeException
      else
        // do something with n
    }
    

    Here the compiler cannot detect if n is indeed even, that is, from the compiler's perspective the following expression is ok:

    f(1)    // compiles OK despite being a logic error!
    

    This program would run and then throw exception at runtime, that is, your program has a logic error.

    Now, dependent types enable you to be much more expressive and would enable you to write something like this:

    def f(n: {n: Integer | n mod 2 == 0}) := {
      // do something with n
    }
    

    Here n is of dependent type {n: Integer | n mod 2 == 0}. It might help to read this out loud as

    n is a member of a set of integers such that each integer is divisible by 2.

    In this case the compiler would detect at compile time a logic error where you have passed an odd number to f and would prevent the program to be executed in the first place:

    f(1)    // compiler error
    

    Here is an illustrative example using Scala path-dependent types of how we might attempt implementing function f satisfying such a requirement:

    case class Integer(v: Int) {
      object IsEven { require(v % 2 == 0) }
      object IsOdd { require(v % 2 != 0) }
    }
    
    def f(n: Integer)(implicit proof: n.IsEven.type) =  { 
      // do something with n safe in the knowledge it is even
    }
    
    val `42` = Integer(42)
    implicit val proof42IsEven = `42`.IsEven
    
    val `1` = Integer(1)
    implicit val proof1IsOdd = `1`.IsOdd
    
    f(`42`) // OK
    f(`1`)  // compile-time error
    

    The key is to notice how value n appears in the type of value proof namely n.IsEven.type:

    def f(n: Integer)(implicit proof: n.IsEven.type)
          ^                           ^
          |                           |
        value                       value
    

    We say type n.IsEven.type depends on the value n hence the term dependent-types.

提交回复
热议问题