TE
TechEcho
Home24h TopNewestBestAskShowJobs
GitHubTwitter
Home

TechEcho

A tech news platform built with Next.js, providing global tech news and discussions.

GitHubTwitter

Home

HomeNewestBestAskShowJobs

Resources

HackerNews APIOriginal HackerNewsNext.js

© 2025 TechEcho. All rights reserved.

Ask HN: Can I have heterogenous lists in a Lisp while preserving type inference?

21 pointsby urs2102over 9 years ago
Trying to see if I can implement type inference on a toy Lisp, but can't figure out what the type of (car '(x y z)) should be in compile time. For those with experience in dealing with types and Lisp, can I keep these heterogenous lists and Hindley-Milner's algorithm W at the same time - or will they naturally run at odds (which is what I'm thinking)?

10 comments

bjourneover 9 years ago
I think you need to run dataflow analysis. There is a paper I read which explains the approach, but I lost the link. It describes how to propagate types to optimize code, but the exact same method can be used to type check code too.<p>Basically the compiler annotates each value it deals with with what it knows about it. So in your example:<p><pre><code> (sqrt (car &#x27;(1 2 &quot;hello&quot;)) </code></pre> First &#x27;(1 2 &quot;hello&quot;) what do we know about it? The value is of type list, the elements types are: integer, integer and string. Since it is a literal, we even know the values: 1, 2, &quot;hello&quot;.<p>We record it somehow. Next we apply car to that value. What do we know about the resulting value? If car was a random function, we wouldn&#x27;t know anything about the result. But car is not random. It is one of the most common Lisp functions so we have custom code for this &quot;known&quot; function that says that its value is the first item of its first parameter.<p>Therefore the type of (car &#x27;(1 2 &quot;hello&quot;) is integer and the value is 1. Since the type of sqrt is an integer N &gt;= 0 (let&#x27;s ignore negative roots), the expression (sqrt (car &#x27;(1 2 &quot;hello&quot;)) type checks! And if we have annotated car and sqrt as side-effect free we can fold the whole expression to 1.<p>Note that if the expression was (sqrt (car &#x27;(x y z)) where x, y, z are unknown variables then it would be a &quot;maybe&quot;. We can&#x27;t know if the code type checks or not. Note also that if the expression was (sqrt (car &#x27;(-1234 y z)), then the code would <i>not</i> type check as (sqrt -1234) has no type (ignoring complex numbers here). That is strictly more powerful than ordinary type systems which can&#x27;t determine that (sqrt -1234) is a programming error.
评论 #10775939 未加载
DonaldFiskover 9 years ago
You want a statically typed Lisp dialect?<p>Why don&#x27;t you just declare your list, say, x, as having type (List Any) where Any is the most general type? (car x) would then have type Any at compile time (i.e you don&#x27;t know its type), so you can&#x27;t take its square root or cons it onto a list of type (List Int), but you could still print it or cons it onto another list of type (List Any).<p>(List Any) then has to be distinct from (List ?x) where ?x is an undetermined type. If y is of type (List ?x) and your function contains (sqrt (car y)), you can infer that ?x is a numeric type and y is a list containing only that type of elements.
评论 #10740850 未加载
justin_vanwover 9 years ago
It depends on the implementation, but even if you have proper type inference, I don&#x27;t understand how it would help with a heterogenous list, since it&#x27;s the heterogenous nature that will prevent optimization anyway, even if you knew exactly what the types were.<p>Most lisps, and certainly common lisp, do not depend on type inference for correct behavior in any way, as they are fundamentally strongly but dynamically typed (like Python). The reason for type inference in Lisps is generally for optimization, where knowing that an array is of type X lets you compile X-specific code for functions that take arrays of type X, and to allow efficient memory layout, where your array is made up of contiguous X objects, rather than storing an array of pointers to X objects, and all the cache missing and so on that this causes (as well as overhead of allocating space for the pointers). Just for completeness, I am saying that in the absence of type information, arrays are always actually arrays of pointers.<p>So lists are always made up of cons cells which contain pointers, so one optimization is out regardless (it is possible that primative types like int or float would be packed into the cons cell itself, but most implementations would achieve this by some kind of bit tagging rather than type information being &#x27;known&#x27;). The other optimization is out because it would likely be equivalent to do dispatch via the usual method for untyped objects rather than trying to do somehow use the type information.
评论 #10740820 未加载
sjayasingheover 9 years ago
I&#x27;m not exactly sure. I think they may be at odds. Scala can handle AnyTypes in lists, but I think you have to decide whether you want compile time type checking or run time dynamic type checking as from my knowledge you can&#x27;t have heterogenous lists in languages like OCaml (and from the little I know of Haskell, Haskell as well).
评论 #10735914 未加载
kazinatorover 9 years ago
&gt; <i>can&#x27;t figure out what the type of (car &#x27;(x y z))</i><p>What? (quote (x y z)) is a constant expression denoting the value (x y z). We know statically that its car is x, of symbol type.
评论 #10743263 未加载
brudgersover 9 years ago
Perhaps it could infer statically typed tuples from heterogeneous types and then apply list semantics to the operations? If the default is immutability, then all lists can be treated that way heterogeneous or not.<p>SMLNJ and other Hindley-Milner based type inferring languages are good at inferring tuples at compile time so there&#x27;s probably a little prior art.
gosubover 9 years ago
could be something like this (with some sugar)?<p><pre><code> data Cons a b = Nil | ConsCell a b cons = ConsCell car Nil = error car (ConsCell a b) = a cdr Nil = error cdr (ConsCell a b) = b mylist = cons &#x27;a&#x27; $ cons True $ cons &quot;hello&quot; Nil mylist :: Cons Char (Cons Bool (Cons [Char] (Cons a b)))</code></pre>
lmmover 9 years ago
AIUI you can&#x27;t have HLists in languages without higher-kinded types, and H-M becomes incomplete in that case.
mveetyover 9 years ago
The actual elements of the lists are typeless basically. The easiest way to do this is that each car of a cons cell is just a pointer to a value (actually both are). Many lisps use tagged pointers where the tag stores the value or even each variable could be a struct with the type and value.
personjerryover 9 years ago
Would this perhaps be a better question for StackOverflow?
评论 #10746721 未加载
评论 #10737705 未加载