1

I am trying to learn a bit of type theory. This is being taught using a dialect of lisp the author wrote called pie.

Let's say we have defined some function f that takes a single argument of type A and produces an output of type B and I have some a that is of type A.

If I try to type the expression:

(f a)

I can't decide between two possible outcomes:

  1. It's a list whose first element is some A->B and whose second element is some A
  2. It's something of type B ... because it's an application

When is a list a list, and when is it an application? What if i wanted lists of functions, how would this work, what's to stop the list being interpreted as an application?

banbh
  • 1,331
  • 1
  • 13
  • 31
Grant
  • 438
  • 2
  • 13
  • When I search for pie Lisp, the most highly-ranked search result that is in any way relevant (e.g. not about the Proto-Indo-European language and such) is ... this StackOverflow question itself. When asking about about obscure dialects, please give a URL. The author wrote this dialect? The author of what, some book or paper on type theory? Which author, what work? – Kaz Dec 25 '19 at 16:20
  • Are you reading this: https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/dimitris-pie.pdf Or is it the *Little Typer*: https://magictea.cc/assets/uploads/files/1549771735966-the.little.typer.2018.9.pdf – Kaz Dec 25 '19 at 16:31
  • It's the little typer. thelittletyper.com I think I is described more as a lisp-like-language rather than a dialect of lisp – Grant Dec 27 '19 at 09:12

3 Answers3

2

When you type it, it is just text (5 characters). When you read it as Lisp syntax, it becomes a list (or form). When you evaluate it, it is evaluated as a function application, which has a value as a result.

In order to write or define a function, the usual symbol is lambda (or λ), which denotes a special operator that creates a function from the rest of the form. For example, to create a function that applies f to a value twice, you might write (lambda (x) (f (f x))).

(The exact semantics may vary a bit depending on the Lisp dialect.)

In order to create a list of something, you use the function list. For example, the following evaluates to a list of two functions:

(list (lambda (x) (f (f x)))
      (lambda (x) (f x)))
Svante
  • 50,694
  • 11
  • 78
  • 122
  • 1
    Ah, I think I understand. This is also helpful as a follow up questions was going to be "what is the need for the list constructor?" So for example if I had a function f and I wanted to apply it to a list of integers I give it, I couldn't write (f (1 2 3)) as lisp would try to evaluate (1 2 3) as an application, I would instead have to write (f (list 1 2 3)). Is this correct? – Grant Dec 23 '19 at 20:55
  • @Grant: Yes, exactly. – Svante Dec 23 '19 at 21:40
2

There's nothing that inherently distinguishes lists from function applications. It's defined entirely by how you use it. If you plan on evaluating it, it's an application (or some other type of program code); otherwise, it's just data.

This is one of the powers of Lisp: it allows you to treat program code as ordinary data as well. This is most apparent in Lisp macros: they take program code, manipulate it as list structure, and return new list structure that's intended to be evaluated in its place.

Note, BTW, that in many Lisp dialects (e.g. Common Lisp), the first element of an application is not a function, it's a function name or lambda expression. E.g. you can do:

(eval (list 'print 3)) # car is the symbol PRINT

but not

(eval (list #'print 3)) # car is the PRINT function.
Barmar
  • 741,623
  • 53
  • 500
  • 612
1

The expression (f a) is a form with f as the first identifier and a as the second. This can never be a list unless f is syntax* (macro).

Thus f gets evaluated to some object which is applied with the evaluated a as argument. If f evaluates to anything else than a function object you'll get an error since it cannot be applied.

You can create literal lists with quote. eg. (quote (f a)) or the syntax abbreviation '(f a) applies the syntax quote which evaluates it's argument as data. eg. a list with two symbols, f and a.

You can create lists dynamically with cons. eg. (cons 'f (cons 'a '())) creates a new list (f a) and (list 'f 'a) is a function that makes a chain of cons with the arguments as elements.

If you wanted to create a list of two functions you can do (cons + (cons - '())) or (list + -) and they are not getting applied because they have no parentheses around them. If you were to do (list (+) (-)) they both get applied with zero arguments and the list results in being (0 0). Note that + and - are just variables here that get evaluated to function objects. You can create new function objects with lambda eg. (lambda (arg) (* arg arg)) is an implementaion of square. They need to be evaluated to become functions so you cannot put them in literals. Eg. '((lambda (arg) (* arg arg)) +) will become a list with the first element being a list with symbol lambda and the second the symbol +. None have anything to do with functions.

Sylwester
  • 47,942
  • 4
  • 47
  • 79
  • 2
    What makes you sure you can "create lists dynamically with `cons`" using OP's "dialect of lisp the author [of some book?] wrote called pie"? Do you know what that is? – Kaz Dec 25 '19 at 16:25
  • @Kaz is correct. The language Pie is similar to scheme or Lisp, but not the same. The only way to create lists in Pie is using the constructor `::`; for example `(:: 42 nil)` creates a list (in fact a `(List Nat)`). The single quote can only be used to create atoms; for example `'hello-world` is an atom. In Pie `cons` is used to construct pairs; for example `(the (Pair Nat Nat) (cons 1 2))` is a pair of `Nat`s. – banbh Feb 09 '20 at 20:19