Search code examples
functionhaskellcoqtype-theory

Representing Functions as Types


A function can be a highly nested structure:

function a(x) {
  return b(c(x), d(e(f(x), g())))
}

First, wondering if a function has an instance. That is, the evaluation of the function being the instance of the function. In that sense, the type is the function, and the instance is the evaluation of it. If it can be, then how to model a function as a type (in some type-theory oriented language like Haskell or Coq).

It's almost like:

type a {
  field: x
  constructor b {
    constructor c {
      parameter: x
    },
    ...
  }
}

But I'm not sure if I'm not on the right track. I know you can say a function has a [return] type. But I'm wondering if a function can be considered a type, and if so, how to model it as a type in a type-theory-oriented language, where it models the actual implementation of the function.


Solution

  • I think the problem is that types based directly on the implementation (let's call them "i-types") don't seem very useful, and we already have good ways of modelling them (called "programs" -- ha ha).

    In your specific example, the full i-type of your function, namely:

    type a {
      field: x
      constructor b {
        constructor c {
          parameter: x
        },
        constructor d {
          constructor e { 
            constructor f { 
              parameter: x 
            } 
            constructor g {
            }
        }
      }
    }
    

    is just a verbose, alternative syntax for the implementation itself. That is, we could write this i-type (in a Haskell-like syntax) as:

    itype a :: a x = b (c x) (d (e (f x) g))
    

    On the other hand, we could convert your function implementation to Haskell term-level syntax directly to write it as:

    a x = b (c x) (d (e (f x) g))
    

    and the i-type and the implementation are exactly the same thing.

    How would you use these i-types? The compiler might use them by deriving argument and return types to type-check the program. (Fortunately, there are well known algorithms, such as Algorithm W, for simultaneously deriving and type-checking argument and return types from i-types of this sort.) Programmers probably wouldn't use i-types directly -- they're too complicated to use for refactoring or reasoning about program behavior. They'd probably want to look at the types derived by the compiler for the arguments and return type.

    In particular, "modelling" these i-types at the type level in Haskell doesn't seem productive. Haskell can already model them at the term level. Just write your i-types as a Haskell program:

    a x = b (c x) (d (e (f x) g))
    b s t = sqrt $ fromIntegral $ length (s ++ t)
    c = show
    d = reverse
    e c ds = show (sum ds + fromIntegral (ord c))
    f n = if even n then 'E' else 'O'
    g = [1.5..5.5]
    

    and don't run it. Congratulations, you've successfully modelled these i-types! You can even use GHCi to query derived argument and return types:

    > :t a
    a :: Floating a => Integer -> a   -- "a" takes an Integer and returns a float
    >
    

    Now, you are perhaps imagining that there are situations where the implementation and i-type would diverge, maybe when you start introducing literal values. For example, maybe you feel like the function f above:

    f n = if even n then 'E' else 'O'
    

    should be assigned a type something like the following, that doesn't depend on the specific literal values:

    type f {
      field: n
      if_then_else {
        constructor even {    -- predicate
          parameter: n
        }
        literal Char          -- then-branch
        literal Char          -- else-branch
    }
    

    Again, though, you'd be better off defining an arbitrary term-level Char, like:

    someChar :: Char
    someChar = undefined
    

    and modeling this i-type at the term-level:

    f n = if even n then someChar else someChar
    

    Again, as long as you don't run the program, you've successfully modelled the i-type of f, can query its argument and return types, type-check it as part of a bigger program, etc.