13

I'm writing a program that for given type signature reconstructs Haskell expression of this type, eg.: for a -> b -> a it returns \x -> \_ -> x. I've read about the theory behind this problem and I know that there is this Howard-Curry isomorphism. I imagine my program to parse input and represent it as terms. Then I would fire SLD-resolution that would tell me if it is possible to construct the term of given type (for Pierce's for instance it is not possible). What I don't already know is how to actually create Haskell expression during this resolution. I've seen the code of djinn but it is a bit complicated, and I want to grasp some general idea of how this works.

Mihai Maruseac
  • 20,967
  • 7
  • 57
  • 109
k_wisniewski
  • 2,439
  • 3
  • 24
  • 31
  • 3
    Before people vote-close, note that the notion of understanding Dijnn is pretty specific and the author of Dijnn frequents SO (and likely not other, more fitting, sites). – Thomas M. DuBuisson Sep 08 '13 at 20:53
  • Yeah, it seems to be a widely known program for solving this problem, but I don't want to copy what the original author has written, but to understand how this works and why. It probably contains some optimizations, but in order to understand their importance I need to have a general idea. Thanks Thomas ;) – k_wisniewski Sep 08 '13 at 20:58
  • Construct Haskell expression from type is like found string from MD5 - is a much harder task then reverse one – wit Sep 08 '13 at 21:51
  • @wit It's much easier than breaking a cryptographic hash. `Djinn> ? x :: a -> b -> (d -> c) -> (a -> b) -> (b -> b -> d) -> c` --> `x a b c d e = c (e (d a) b)`. – Thomas M. DuBuisson Sep 08 '13 at 22:51
  • 1
    Do you want to construct the actual Haskell value or a syntax tree that you can print out? If it's the latter, just define a type for expression. Minimally, variables, abstraction, application. SLD resolution is not an easy way to get computational contents. You need a proof procedure for intuitionistic logic. – augustss Sep 08 '13 at 22:54
  • @augustss - in the basic case I could just print the resulting function, but if this does not add too much complexity it would be nice to be able to generate the actual Haskell value. What procedure would you recommend instead of SLD-resolution? I haven't dealt with intuitionistic logic before, the only thing I know is what I've just read on wikipedia :) I've seen that you are using something called LJT in Djinn - can you outline how it works and why is this a better choice (if it is)? – k_wisniewski Sep 08 '13 at 23:18
  • @k_wisniewski Do you know about the (very slightly bit rotted) djinn-th? It allows you to use djinn to generate Haskell code/values that match a particular type. – Thomas M. DuBuisson Sep 09 '13 at 00:53
  • I haven't found this before, thanks Thomas! – k_wisniewski Sep 10 '13 at 08:07
  • Maybe look at djinn and ask specific questions about what you don't understand , or some general questions about its structure. – misterbee Dec 28 '13 at 16:36
  • possible duplicate of [How does Djinn work?](http://stackoverflow.com/questions/10217931/how-does-djinn-work) – SamB Jan 19 '14 at 04:13

1 Answers1

1

If you use Curry-Howard to connect a subset of Haskell to some intuitionistic logic, it should be very easy to extract a Haskell program from a proof term. Essentially, the proof terms should already have the very same structure as Haskell programs, but just use different constructor names. I think you can even use the same algebraic data type for both proof terms and Haskell terms if you translate the constructor names in your head as appropriate. For example:

type Name = String

data Type                  -- aka. Formula
  = Function Type Type     -- aka. Implication
  | TypeVar Name           -- aka. PropositionalVar

data Term                  -- aka. Proof
  = Lambda Name Type Term  -- aka. ImplicationIntroduction
  | Apply Term Term        -- aka. ImplicationElimination
  | TermVar Name           -- aka. Start / Identity / Axiom / Copy

You will have to use a context of variables in scope (aka. hypotheses you can assume).

type TypingContext = Map Name Type -- aka. Hypotheses

Given types like this, you "just" have to write a function:

termOf :: Type -> TypingContext -> Maybe Term

But maybe as a first step, it would be better to write the inverse function first, as an exercise:

typeOf :: Term -> TypingContext -> Maybe Type

The basic structure of these two function should be similar: Pattern match on the thing you have, decide which typing rules (aka. proof rules) are applicable, call yourself recursively to construct a partial result, finish the partial result by wrapping in the constructor that corresponds to the typing rule (aka. proof rule). A difference is that typeOf can just walk through the whole term and figure everything out, while termOf probably has to guess and backtrack if guesses don't work out. So probably, you actually want the list monad for termOf.

The benefit of writing typeOf first is:

  1. It should be easier because terms tend to contain more information than types, so termOf can use that extra information while typeOf needs to create that extra information.
  2. There is more help available because many people implement typeOf as an exercise but few people implement termOf as an exercise.
Toxaris
  • 7,156
  • 1
  • 21
  • 37