
Statically Typed Lisp - _qc3o
https://gist.github.com/chrisdone/516489f4f27846712225#file-anintro-md
======
jarcane
So ... Typed Racket then? [http://docs.racket-lang.org/ts-
guide/](http://docs.racket-lang.org/ts-guide/)

~~~
spdegabrielle
An example

#lang typed/racket ;; Using higher-order occurrence typing (define-type SrN (U
String Number)) (: tog ((Listof SrN) -> String)) (define (tog l) (apply
string-append (filter string? l))) (tog (list 5 "hello " 1/2 "world" (sqrt
-1)))

~~~
dschiptsov
Which is the same algebraic data types - a list of touples.

------
dschiptsov
Very clever toy example.

One of definitive features of Lisps is heterogeneous lists, upon which other
features, such as code-generation and hence macros has been built.

All the cleverness of static typing falls apart with heterogeneous lists.
That's why we don't have them in Standard ML or Haskell. So, in Lisps we trade
static typing for power and flexibility of layered DSLs based on special forms
(advanced macros). typecase macro, CLOS, structure-based pattern-marching
modules are examples of such DSLs. Strong typing is good-enough.

This is just my opinion, of course. Lisp has been evolved with its own way.
Like famous quote form evolutionary psychology (or biology?) goes -
_Everything is the way it is because it got that way._

[http://karma-engineering.com/lab/wiki/Languages](http://karma-
engineering.com/lab/wiki/Languages)

[http://karma-engineering.com/lab/wiki/Bootstrapping2](http://karma-
engineering.com/lab/wiki/Bootstrapping2)

~~~
noelwelsh
I don't think this is really accurate anymore. Using the list data type as the
compiler's internal representation causes problems as there is nowhere to
store information the compiler needs need, such as locations for error
reporting, or value representation for optimisation, and so on. You either end
up using some awful hack (e.g. the second element of each list is an a-list of
compiler specific info) or you use a different data type. This latter is the
approach that Racket, the Lisp I'm most familiar with, takes. Programs are
represented using a "syntax" data structure that is not list, though it can be
converted into one.

See HLists (e.g.
[https://hackage.haskell.org/package/HList](https://hackage.haskell.org/package/HList))
for heterogeneous lists in Haskell. The techniques for implementing these are
relatively (last 10 years or so).

~~~
dschiptsov
The problem is very simple - as long as a list is homogenous or it is a finite
either-of algebraic data type, you could infer the type of a function on these
- it could be a another homogenous list or a value if some other type.

As long as a list could contain anything then it could be mapped to another
list of anything (a list of symbols, numbers, etc.) Or a value. Basically, we
could say a pointer or a list of pointers, which by definition could point to
any kind of a type-tagged value.

Types a-la

    
    
       (* -> *) -> [*] -> [*] 
    

are't very useful, but this is what we have in Lisps.

Moreover, as long as there is no difference between a pointer to a list and
pointer to a value (these are just bindings of symbols to type-tagged values)
we could have procedures of type

    
    
       * -> * -> * 
    

Lisp stands for LISt Processing after all, for performing so-called symbolic
manipulations (like our minds do) and this is a pretty good "type" for a
procedure doing a symbolic transformation.

So, all the values have type-tags. Add NIL and T, structural types such as
arrays or structs, and you will get a crude type hierarchy of a Lisp.

Our lists aren't sets (homogenous) so all the typing based on Set theory is of
no use.

~~~
noelwelsh
My first paragraph was referring to lists (not) being the internal
representation of programs within (modern) Lisps. Nothing about heterogeneous
lists or type theory there.

Second paragraph is about heterogeneous lists.

~~~
dschiptsov
I am sorry, I am not a type theorist. Someone added a link to an attempt of
define a statically-typed Lisp. I am suggesting to try to look deeper what a
Lisp is and why it is the way it is.

------
tempodox
Sadly, statically typed Lisp is a contradiction in terms. It would be in the
same category as dynamically typed Haskell.

But the experiment shows nicely how little you need to bootstrap something
lispy.

~~~
xenophonf
I've said it before, but I'll say it again. Common Lisp already features
strong static typing (the example below uses SBCL):

    
    
      * (defun foo (x) x)
    
      FOO
      * (declaim (ftype (function (fixnum)) foo))
    
      * (defun bar (y) (declare (string y)) (foo y))
      ; in: DEFUN BAR
      ;     (FOO Y)
      ; 
      ; caught WARNING:
      ;   Derived type of Y is
      ;     (VALUES STRING &OPTIONAL),
      ;   conflicting with its asserted type
      ;     FIXNUM.
      ;   See also:
      ;     The SBCL Manual, Node "Handling of Types"
      ; 
      ; compilation unit finished
      ;   caught 1 WARNING condition
    
      BAR
    

One could also declare the function signature first (perhaps in skeleton code
generated by modelling tools). Then, if someone implements it incorrectly, the
compiler will throw an error (again, SBCL):

    
    
      * (declaim (ftype (function (fixnum)) qux))
    
      * (defun qux (z) (car z))
      ; in: DEFUN QUX
      ;     (CAR Z)
      ; 
      ; caught WARNING:
      ;   Derived type of Z is
      ;     (VALUES FIXNUM &OPTIONAL),
      ;   conflicting with its asserted type
      ;     LIST.
      ;   See also:
      ;     The SBCL Manual, Node "Handling of Types"
      ; 
      ; compilation unit finished
      ;   caught 1 WARNING condition
    
      QUX
    

Here's a good discussion of static typing in Common Lisp:

[http://www.lispforum.com/viewtopic.php?f=2&t=191](http://www.lispforum.com/viewtopic.php?f=2&t=191)

TL;DR is that many CL implementations will check types at compile time, but
for appropriate speed and safety settings, they will also generate code that
checks types at runtime, too.

~~~
tempodox
This is, of course, correct and I do use that technique in SBCL myself, but it
still doesn't make SBCL a statically typed language (even if SBCL has the
strictest type checks and the best native code generation I've seen in an
open-source Lisp to date). The static typing in OCaml, Haskell - heck, even C
is still another thing.

~~~
xenophonf
I don't know OCaml or Haskell, but I think you're mistaken about C. Given the
following C code:

    
    
      char *foo(char *bar) {
        return bar;
      }
      
      int main(int argc, char *argv[]) {
        foo(1);
        return 0;
      }
    

I get compile-time warnings from clang substantially similar to what SBCL
emits:

    
    
      $ cc test.c 
      test.c:6:7: warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'char *' [-Wint-conversion]
        foo(1);
            ^
      test.c:1:17: note: passing argument to parameter 'bar' here
      char *foo(char *bar) {
                      ^
      1 warning generated.
    

I'm sure that with suitable flags set, both compilers would throw type errors
at compile-time instead of warnings.

