If a language is not Turing complete, there are computational problems it cannot solve. So, purely from a view internal to the language, you can't necessarily do everything you want. If you want to use a non-Turing complete language to design some kind of computer architecture, you'll also run into problems.
A Turing Complete system means a system in which a program can be written that will find an answer (although with no guarantees regarding runtime or memory). So, if somebody says "my new thing is Turing Complete" that means in principle (although often not in practice) it could be used to solve any computation problem.
Typically, one proves a given language is Turing-complete by providing a recipe for translating any given Turing machine program into an equivalent program in the language in question. Alternately, one can provide a translation scheme from another language, one that has already been proven to be Turing-complete.
Advantages of a Turing Complete SystemThis approach works great for problems that have predefined steps and solutions (such as most arithmetic problems) but can lead to problems when it comes to undecidable problems.
There is a blog post somewhere with a type-level implementation of the SKI combinator calculus, which is known to be Turing-complete.
Turing-complete type systems have basically the same benefits and drawbacks that Turing-complete languages have: you can do anything, but you can prove very little. In particular, you cannot prove that you will actually eventually do something.
One example of type-level computation are the new type-preserving collection transformers in Scala 2.8. In Scala 2.8, methods like map
, filter
and so on are guaranteed to return a collection of the same type that they were called on. So, if you filter
a Set[Int]
, you get back a Set[Int]
and if you map
a List[String]
you get back a List[Whatever the return type of the anonymous function is]
.
Now, as you can see, map
can actually transform the element type. So, what happens if the new element type cannot be represented with the original collection type? Example: a BitSet
can only contain fixed-width integers. So, what happens if you have a BitSet[Short]
and you map each number to its string representation?
someBitSet map { _.toString() }
The result would be a BitSet[String]
, but that's impossible. So, Scala chooses the most derived supertype of BitSet
, which can hold a String
, which in this case is a Set[String]
.
All of this computation is going on during compile time, or more precisely during type checking time, using type-level functions. Thus, it is statically guaranteed to be type-safe, even though the types are actually computed and thus not known at design time.
My blog post on encoding the SKI calculus in the Scala type system shows Turing completeness.
For some simple type level computations there are also some examples on how to encode the natural numbers and addition/multiplication.
Finally there is a great series of articles on type level programming over on Apocalisp's blog.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With