How to draw a type-inference parse tree for sml

后端 未结 1 1399
别跟我提以往
别跟我提以往 2021-01-28 12:22

So I am working on my practice final, there is problem ask me to draw a parse tree for this sml code:

fun ff f x y = if (f x y) then (f 3 y) else (f x \"zero\")         


        
相关标签:
1条回答
  • 2021-01-28 13:09

    The simplest way I can think of is to slightly reformat your code and basically put each subexpression on its own line. Children are denoted by increased indentation.

    Let's take your example:

    fun ff f x y = if (f x y) then (f 3 y) else (f x "zero")
    

    First, we need to do a little desugaring. The above is equivalent to this:

    val ff =
      fn f =>
        fn x =>
          fn y =>
            if (f x y) then (f 3 y) else (f x "zero")
    

    Now, let's put each subexpression on its own line (the parantheses are redundant in this particular example; everything works fine without them):

    val ff =
      fn f =>
        fn x =>
          fn y =>
            if
              f
                x
                  y
              then
                f
                  3
                    y
              else
                f
                  x
                    "zero"
    

    Finally, let's attach a type to each subexpression, but let's use type variables for types we don't know yet. Notice we're using the same type variables for the same occurrences. For example x has type t3 everywhere.

    Subexpression          | Type
    ---------------------- | ------------------------------------------
    val ff =               | t0
      fn f =>              | t1 -> t2
        fn x =>            | t3 -> t4
          fn y =>          | t5 -> t6
            if             | t7 (* the type of the whole `if` expression *)
              f            | t1
                x          | t3
                  y        | t5
              then         | t8 (* the type of the whole `then` part *)
                f          | t1
                  3        | int
                    y      | t5
              else         | t9 (* the type of the whole `else` part *)
                f          | t1
                  x        | t3
                    "zero" | string
    

    You can then do some further simplifications by noticing that some type variables are equivalent or that they're used in certain contexts. For example, from these three calls to f:

    • f x y
    • f 2 y
    • f x "zero"

    we can gather that x must be of type int and y must be of type string. So, let's replace the type of x, that is t3, with int, and the type of y, that is t5, with string. We do this everywhere:

    Subexpression          | Type
    ---------------------- | ------------------------------------------
    val ff =               | t0
      fn f =>              | t1 -> t2
        fn x =>            | int -> t4
          fn y =>          | string -> t6
            if             | t7
              f            | t1
                x          | int
                  y        | string
              then         | t8
                f          | t1
                  3        | int
                    y      | string
              else         | t9
                f          | t1
                  x        | int
                    "zero" | string
    

    Also, f is used as a function that is being passed an int each time. The result is also used as a function and is being passed a string. That means t1, which is the type variable assigned to f, must be of type int -> string -> r0, for some r0 we don't know yet. Let's replace all occurrences of t1 with int -> string -> r0.

    Subexpression          | Type
    ---------------------- | ------------------------------------------
    val ff =               | t0
      fn f =>              | (int -> string -> r0) -> t2
        fn x =>            | int -> t4
          fn y =>          | string -> t6
            if             | t7
              f            | int -> string -> r0
                x          | int
                  y        | string
              then         | t8
                f          | int -> string -> r0
                  3        | int
                    y      | string
              else         | t9
                f          | int -> string -> r0
                  x        | int
                    "zero" | string
    

    But notice something, r0 must be treated as a bool, because the result of f x y is used in the condition part of an if expression, so let's replace r0 with bool everywhere:

    Subexpression          | Type
    ---------------------- | ------------------------------------------
    val ff =               | t0
      fn f =>              | (int -> string -> bool) -> t2
        fn x =>            | int -> t4
          fn y =>          | string -> t6
            if             | t7
              f            | int -> string -> bool
                x          | int
                  y        | string
              then         | t8
                f          | int -> string -> bool
                  3        | int
                    y      | string
              else         | t9
                f          | int -> string -> bool
                  x        | int
                    "zero" | string
    

    Next, the type of the whole if expression must be the same as the type of the then part, which must be the same as the type of the else part. So t7, t8 and t9 must all be the same. Let's use t7 where we see t8 and t9.

    Subexpression          | Type
    ---------------------- | ------------------------------------------
    val ff =               | t0
      fn f =>              | (int -> string -> bool) -> t2
        fn x =>            | int -> t4
          fn y =>          | string -> t6
            if             | t7
              f            | int -> string -> bool
                x          | int
                  y        | string
              then         | t7
                f          | int -> string -> bool
                  3        | int
                    y      | string
              else         | t7
                f          | int -> string -> bool
                  x        | int
                    "zero" | string
    

    Next, t7 must be of type bool because the type of both f 3 y and f x "zero" is bool:

    Subexpression          | Type
    ---------------------- | ------------------------------------------
    val ff =               | t0
      fn f =>              | (int -> string -> bool) -> t2
        fn x =>            | int -> t4
          fn y =>          | string -> t6
            if             | bool
              f            | int -> string -> bool
                x          | int
                  y        | string
              then         | bool
                f          | int -> string -> bool
                  3        | int
                    y      | string
              else         | bool
                f          | int -> string -> bool
                  x        | int
                    "zero" | string
    

    Next, t6 must be a bool too, because we're returning the result of the if expression:

    Subexpression          | Type
    ---------------------- | ------------------------------------------
    val ff =               | t0
      fn f =>              | (int -> string -> bool) -> t2
        fn x =>            | int -> t4
          fn y =>          | string -> bool
            if             | bool
              f            | int -> string -> bool
                x          | int
                  y        | string
              then         | bool
                f          | int -> string -> bool
                  3        | int
                    y      | string
              else         | bool
                f          | int -> string -> bool
                  x        | int
                    "zero" | string
    

    Next, t4 must be of type string -> bool, because that's what the type of its body is:

    Subexpression          | Type
    ---------------------- | ------------------------------------------
    val ff =               | t0
      fn f =>              | (int -> string -> bool) -> t2
        fn x =>            | int -> string -> bool
          fn y =>          | string -> bool
            if             | bool
              f            | int -> string -> bool
                x          | int
                  y        | string
              then         | bool
                f          | int -> string -> bool
                  3        | int
                    y      | string
              else         | bool
                f          | int -> string -> bool
                  x        | int
                    "zero" | string
    

    What's t2? It must be the type of the body, which is int -> string -> bool:

    Subexpression          | Type
    ---------------------- | ------------------------------------------
    val ff =               | t0
      fn f =>              | (int -> string -> bool) -> int -> string -> bool
        fn x =>            | int -> string -> bool
          fn y =>          | string -> bool
            if             | bool
              f            | int -> string -> bool
                x          | int
                  y        | string
              then         | bool
                f          | int -> string -> bool
                  3        | int
                    y      | string
              else         | bool
                f          | int -> string -> bool
                  x        | int
                    "zero" | string
    

    Finally, the type t0 of ff must be equal with the type of the value assigned to ff. So:

    Subexpression          | Type
    ---------------------- | ------------------------------------------
    val ff =               | (int -> string -> bool) -> int -> string -> bool
      fn f =>              | (int -> string -> bool) -> int -> string -> bool
        fn x =>            | int -> string -> bool
          fn y =>          | string -> bool
            if             | bool
              f            | int -> string -> bool
                x          | int
                  y        | string
              then         | bool
                f          | int -> string -> bool
                  3        | int
                    y      | string
              else         | bool
                f          | int -> string -> bool
                  x        | int
                    "zero" | string
    

    And that's your final result.

    0 讨论(0)
提交回复
热议问题