Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> There is value in static checking for some things, but it is also limiting.

Other than type-safe heterogenous lists(which is only true if you hold static type systems to a much higher standard of type-safety than dynamic type systems), what sorts of things do a type system with type classes, algebraic data types, and higher order functions prevent doing?

> Lisps can and do have powerful type systems - you're confusing dynamic with none at all.

Common Lisp has a powerful object system and dispatch scheme, but it isn't as powerful as Haskell's type system. Type classes provide compile-time multi-methods which can be every bit as dynamic as CLOS's when needed, but which are statically checked as much as is possible. In addition, type classes make it possible to dispatch not just on argument type but also on return type. How do you write a Common Lisp function which polymorphicly converts an integer to whatever type you need? This is admittedly a bit of a weak example, but polymorphic conversions like this can probably be useful(for example, you could use it to implement a somewhat inefficient heterogenous list).

In Haskell(I'm not very familiar with Haskell, but my testing indicates that this would work): class FromInt t where fromInt :: Integer -> t

Haskell also has parameterized types, which aren't as needed in dynamic type systems, but that relative lack of need is only because a dynamic type systems considers a program that calls a method which doesn't work on an object's type at runtime to be type-safe.

In a statically typed language with type classes and sufficiently powerful syntactic macros, it would be possible to conveniently defer to dynamic type checking in way that would type-check statically. The macros are only necessary for the convenience part. Otherwise, you'd have to create a lot of type classes for every type you wanted to use dynamically. With macros, you could just include the creation of the appropriate classes in the form that defines a new type. In fact, it could be built into the language making even macros unnecessary.



>Other than type-safe heterogenous lists(which is only true if you hold static type systems to a much higher standard of type-safety than dynamic type systems), what sorts of things do a type system with type classes, algebraic data types, and higher order functions prevent doing?

Automatic serializing and deserializing of objects. I wrote the RJson library for Haskell to do this for JSON, but there is no way I would ever write anything like that in Haskell again. Using a statically typed language makes it necessary to use horribly complicated types and (in the case of RJson at least) to lose the guarantee that the program's types are decidable. Also, you tend to find that as the type system grows more sophisticated than basic Haskell 98, there is a much greater likelihood of incorrect programs type-checking correctly, so this becomes a less useful means of preventing errors. In writing RJson, I frequently had to determine the correct types for functions by trial and error -- it kinda defeats the purpose of strong typing when a function's type is harder to understand than the function itself.

In a language like Python or Lisp, with decent reflective capabilities, writing the equivalent library would be a whole ton easier.


CLOS is runtime dynamic. Haskell is not. Haskell is a mostly static language. Common Lisp is a mostly dynamic language and provides all kinds of mechanism to make changes at runtime to the language and programs written in Lisp. The CLOS Meta-Object Protocol allows various ways to change the object system. This has been used for various object-oriented languages on top of Lisp, user interfaces, databases and other stuff.

The 'dynamic' part of Common Lisp means that is a runtime programmable programming language.

Haskell and Common Lisp serve totally different purposes. Common Lisp is there for incremental, interactive development of complex software - software that is always running in the development process and gets modified until is does something useful. Software that also can be modified when deployed, while running.


> How do you write a Common Lisp function which polymorphicly converts an integer to whatever type you need?

How does the callee know what the caller needs?

Suppose that one callee produces an int (as above), the first caller wants a string (decimal digits in ascii) and the second wants a byte array (little endian). Do you really think that the caller (or compiler) should be responsible for accomodating those conversions? Now let's add a caller that wants the index of the "high bit" - how are you going to accomodate that? (Of course, other callers want an int - I'm just mentioning the callers that require some sort of conversion.)

Neither the callee nor the compiler/system can automatically provide anything beyond the most trivial of conversions. That's why the right solution to the third caller, either an in-line shim or a wrapper, is the right solution to either the first or second caller.

> With macros, you could just include the creation of the appropriate classes in the form that defines a new type. In fact, it could be built into the language making even macros unnecessary.

Lisp macros can do many other things. (Consider the loop construct.)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: