
Writing custom type systems for Python in Prolog - type0
http://code.alehander42.me/prolog_type_systems
======
bjz_
> Everybody who does PL theory more seriously probably knows that, but I
> didn't realize how close type inference and prolog-like systems look.

Yup! This is more to do with a very specific part of type theory - ie. 'type
reconstruction' (more commonly referred to as 'type inference'). One of the
most notable examples of this is the so-called 'Hindley-Milner type system'
which can be proven to decidable. Here is a good explanation of the
constraint-solving algorithm:
[http://jozefg.bitbucket.org/posts/2015-02-28-type-
inference....](http://jozefg.bitbucket.org/posts/2015-02-28-type-
inference.html)

~~~
baq
I've looked at Prolog for implementing a rule-based workflow system, but I
find that it's very hard to embed eg. SWI Prolog into Python, in which the
rest of the project is written. Does anyone know of an embeddable Prolog,
preferably open source?

~~~
junke
ECLiPSe, for example. See [1] for documentation about how to embed it.
However, this is targetted at C, Java and Tcl/Tk, not Python. Another approach
is to use a client/server approach with two processes (python starts a
background prolog, for example).

[1]
[http://eclipseclp.org/doc/embedding/embroot.html](http://eclipseclp.org/doc/embedding/embroot.html)

------
YeGoblynQueenne
>> Is there a deeper link between logical programming and type theory?

There is: types are pattern that data must conform to (and operations also-
so, data). To declare a value "x" as having the type "int" is to assert that
"x" matches whatever pattern "int" stands for.

The connection to logic programming is that logic programming languages,
certainly Prolog, are implemented as relational databases with a search
procedure using pattern matching to find relations that conform to the pattern
of a query. The pattern matching algorithm in Prolog is called unification:
it's like the pattern matching in regular expressions, only Turing complete,
so it can represent any program. In fact, Prolog programs _are_ patterns
representing themselves [1]. But let's not get too excited.

Prolog's pattern matching makes it indeed very convenient for representing
types, even complex types and nested hierarchies of such. For example, Haskell
uses something very similar to unification for its type inference system [2].

However- a word of caution. Doing simple type inference ish is not that
complicated in Prolog (at least if you're doing it as an exercise- doing it
industrial-strength would take a lot of effort). Doing something more
complicated, like representing Hindley-Milner like in [3], is more of an
undertaking, which is (partly) why Prolog itself doesn't have any types in the
conventional sense. Then again predicates with implicitly universally
quantified variables are themselves types, er, implicitly, so in a way each
Prolog program declares its own type system exactly matching itself.

See [4] for a discussion of logic progamming, types and category theory (I'm
not affiliated with the author in any way).

_______________

[1]
[https://en.wikipedia.org/wiki/Homoiconicity#Homoiconicity_in...](https://en.wikipedia.org/wiki/Homoiconicity#Homoiconicity_in_Prolog)

[2]
[https://wiki.haskell.org/Type_inference](https://wiki.haskell.org/Type_inference)

[3] [http://www.swi-prolog.org/pack/list?p=type_check](http://www.swi-
prolog.org/pack/list?p=type_check)

[4] [http://www.drdobbs.com/what-might-category-theory-do-for-
art...](http://www.drdobbs.com/what-might-category-theory-do-for-
artifi/228700165)

~~~
agumonkey
Ocaml type inference has subtle variations on this I believe, according to
kiselyov it links GC and TC
[http://okmij.org/ftp/ML/generalization.html](http://okmij.org/ftp/ML/generalization.html)

~~~
asQuirreL
The variations are in the implementation detail, the type checking algorithm
that Kiselyov describes in your link is extensionally equivalent to Algorithm
W. OCaml's type checker is slightly different to HM, but only to deal with the
type semantics of things that HM was not originally meant to deal with (like
mutable references for instance).

The link Kiselyov mentions is between Garbage collection (-ish, really it's
more lifetime analysis a la Rust) and when it is appropriate to generalise a
free type variable and how they both interact with aliasing. Take the
following expression:

    
    
        fun (x) let y = x in y
    

Here's what we expect:

* It has type `forall 'a . 'a -> 'a` (Keeping the universal quantification explicit).

* The value held in `y` outlives the scope of `y`, because it is aliased in `x`.

But the naïve solution results in:

* The type `forall 'a 'b . 'a -> 'b` (Any function of this type is pure sorcery)

* The value of `y` (and `x`) gets deallocated at the end of `y`'s scope.

The solution is that each type variable should keep track of the scope it was
introduced in (like de Bruijn indices), and when generalising, we only
universally quantify variables at more deeply nested scopes (which corresponds
to deallocating unreachable things).

------
qwertyuiop924
This has singlehandedly made me interested in learning more about prolog. I
mean, if you can do things like that that simply... Holy crap. No wonder so
many lisps incude a prolog implementation of some sort.

~~~
coliveira
Prolog was designed to do this kind of things easily. You can parse languages
with easy, and perform all kinds of programming transformations that would
take thousands of lines in other languages in just a few rules. The problem
with prolog is when you try to do the run-of-the-mill stuff. Not because it is
impossible or even hard, but because you need to change the way you think
about programming. This is very difficult for programmers that are already
used to imperative languages.

~~~
chubot
Really, how does it handle parsing? What kind of languages can you parse?

I recall this paper, by Joe Armstrong of Erlang... I'll have to go read it
again.

"Use of Prolog for developing a new programming language"

[https://scholar.google.com/scholar?cluster=23466104209097450...](https://scholar.google.com/scholar?cluster=2346610420909745067&hl=en&as_sdt=0,5&sciodt=0,5)

Hm after scanning it, I think the reason I never really got it the first time
around is that I don't know Prolog :) Might be time to fix that.

What turned me off to Prolog is that there's no way to reason about the
computational complexity of the algorithm. Declarative languages often have
this problem. That's why you have SQL queries that literally take thousands of
times longer than a Python script in production (hours vs seconds).
Programming models also need performance models.

~~~
abecedarius
[https://en.wikipedia.org/wiki/Definite_clause_grammar](https://en.wikipedia.org/wiki/Definite_clause_grammar)
\-- parsing in Prolog. As usual with Wikipedia on technical topics it looks
like a poor introduction, sorry.

Reasoning about performance is quite possible; there's good advice in Richard
O'Keefe's _The Craft of Prolog_.

[Edit: fixed the book title, thanks to a friendly correction. _The Practice of
Prolog_ is a different book, also good, but less relevant.]

~~~
qohen
_As usual with Wikipedia on technical topics it looks like a poor
introduction, sorry._

There are real tutorials on DCGs available, e.g.

[http://www.pathwayslms.com/swipltuts/dcg/](http://www.pathwayslms.com/swipltuts/dcg/)

(BTW, SWI-Prolog, which the tutorial uses, is freely available here:

[http://www.swi-prolog.org/](http://www.swi-prolog.org/) )

~~~
qohen
Also, if you want to dive deeper, the book, "Prolog and Natural Language
Analysis" by Fernando C. N. Pereira and Stuart M. Shieber, is available as a
free PDF from the publisher:

[http://www.mtome.com/Publications/PNLA/prolog-
digital.pdf](http://www.mtome.com/Publications/PNLA/prolog-digital.pdf)

And there's a set of course materials in HTML for "Natural Language Processing
in Prolog", a course at Union College in Schenectady, NY by Patrick Blackburn
and Kristina Striegnitz that seems worthwhile:

[http://cs.union.edu/~striegnk/courses/nlp-with-
prolog/html/t...](http://cs.union.edu/~striegnk/courses/nlp-with-
prolog/html/toc.html)

------
ittekimasu
Sweet! I've always wished a better type systems were available in dynamic
languages.

These deficiencies are clearly visible in Lisps where you're given great meta-
power with macros, but where the type system starts fighting petulantly,
whenever one wants to do something fast. In this respect C++ templates are
much better.

Shen on the other hand seems quite interesting (and seems to come with its own
prolog engine!); anyone here have any views on this Lisp ?

~~~
bjz_
Also be sure to check out typed racket!

~~~
jakub_h
Sadly, Typed Racket always seemed to me like some kind of shoehorning an ad-
hoc system onto an AST. For that purpose, a deductive system seems much more
natural. There may be problems with decidability, but the fortuitous thing is
that this is not a deal-breaker for a primarily dynamic language. You should
always be able to rewrite your modules so that they're easier to check, but
even if you can't do that outright, the system could still find faster
versions if a few type guards or other invariant checks get inserted here and
there, or perhaps some form of assistant in your development environment could
hint at the need to insert them manually.

------
mcguire
Anyone have any thoughts on an idea I've been pondering for a while: Prolog as
the type system for dependant typing?

The type systems I've seen for dependantly typed languages have mostly tried
to use traditional formal logic syntax, with resulting usability issues and
frequently a mismatch with the programming language.

For example, ATS is based on ML syntax, but the typing frequently results in
functions of the form:

    
    
        fun foo =
          let _ = ...
              x = ...
              _ = ...
          in
            ()
    

So, why not use a programming language for type-level programming?

~~~
tom_mellior
> Anyone have any thoughts on an idea I've been pondering for a while: Prolog
> as a type system [...] traditional formal logic syntax, with resulting
> usability issues

You haven't really explained what your idea is or how Prolog differs from
"traditional formal logic syntax". If anything, Prolog's predicate syntax is
closer to formal logic than the many ML-based dependently typed programming
languages; except that quantifiers are implicit in Prolog.

Anyway, you might want to look around
[http://homepages.inf.ed.ac.uk/jcheney/programs/aprolog/](http://homepages.inf.ed.ac.uk/jcheney/programs/aprolog/)
and espectially
[http://www.lix.polytechnique.fr/~dale/lProlog/](http://www.lix.polytechnique.fr/~dale/lProlog/)

> requently a mismatch with the programming language

I find Coq's syntax fairly regular in this regard. (The syntax for expressing
computations and predicates, _not_ the tactic and tactical syntaxes.)

> So, why not use a programming language for type-level programming?

Because of the "mismatch with the programming language" that you yourself have
identified as a problem.

------
Johnny_Brahms
In my programming career 3 languages have changed how I look at programming.
The first one was scheme which is still my go to language for most of my
personal projects. The second one was prolog and the third was Forth/factor.

Whenever someone asks where to "widen their view" I generally recommend prolog
or factor (15 years ago, I would have said scheme, but lisps seem to have been
all the rage so I no longer need to).

~~~
bogomipz
Can you elaborate on what is special about Forth? I see Forth articles show up
on HN now and again but I've been able to glean why its special to so many. I
know its been around forever.

~~~
tom_mellior
> Can you elaborate on what is special about Forth?

Not the OP here, but I'll give it a partial shot. The power of Forth comes
from its extremely simple syntax and the ways you can extend it. A Forth
program is just a sequence of "words", which are any sequences of non-
whitespace characters separated by whitespace. Users can define new words.
These can be "parsing words" which can consume the input that follows them in
arbitrary ways.

So, for example, given appropriate definitions, this is a valid Forth program:

    
    
        ax bx mov             \ mov ebx,eax
        3 # ax mov            \ mov eax,3
    

(this is taken directly from GForth's inline assembly docs:
[https://www.complang.tuwien.ac.at/forth/gforth/Docs-
html/386...](https://www.complang.tuwien.ac.at/forth/gforth/Docs-
html/386-Assembler.html#g_t386-Assembler) ; the \ introduces a comment to the
end of the line and shows the assembly code as it would be written in a
traditional assembler)

Or, given appropriate definitions, this is a valid Forth program:

    
    
        select * from customers
    

You see where this is going: Programmers have a _lot_ of possibilities to
extend the language or implement embedded DSLs (which is pretty much the same
thing in Forth). A popular demo of this power are things along the line of
[http://c2.com/cgi/wiki?ForthObjects](http://c2.com/cgi/wiki?ForthObjects),
where an object system for Forth (which is not object oriented at all) is
implemented in 20 lines of code.

All that said, it's ugly and complex and I always find it difficult to figure
out what's going on with all the strangely named concepts and compile-time
effects and run-time effects of everything. But still. Interesting stuff.

~~~
bogomipz
Thank you, I certainly see the power in that. Thanks for the time to answer.

------
bobsh
The definition of Standard ML is perhaps where the OP might like to look, for
a somewhat more advanced example.

