Live data from Hacker News

Rust's type system is Turing-complete (2017)

sdleffler.github.io

31–40 of 91 posts

Re: Rust's type system is Turing-complete (2017)

#31
post #24

Earlier quoted context omitted.

You do realize that you're moving part of the cognitive load until later and increasing it when you have to implement a type checker in unit tests for every program you write.

Yes and? I have the full power of the language to force type correctness instead of some janky meta language.

Most dependently typed languages allow you to use the full power of the language to specify types.

Re: Rust's type system is Turing-complete (2017)

#32

One of the reasons I like weak type systems or duck typing as is with vanilla JS is because I don't have cognitive overload... I don't have to think about abstractions as types I only need to think how to solve the problem in front of me. My unit tests can check for correctness after I've solved the problem. The fact that you can have Turing completeness in a type-system (not the language itself but within it's type…

I think we should strive for strong type systems with a lot of type inference. I especially like Typescript for that.

Type systems are very useful to establish the semantics of your operations. For example `int + int` is not the same operation as `string + string`, and definitely not the same as `int + string` (which does not exist in most languages). You could call `+` an addition, but addition only exists for numbers, for strings it is a concatenation.

Is `int + string` the same as `string + int` ? (commutativity)

Is `int + int + string` the same as `(int + int) + string` or `int + (int + string)`? In that case, what does `int + string` returns? (associativity)

Now consider this code:

  def foo(a, b):
    return a + b
vs

  function foo(a: int, b: string) {
    return a + b
  }
In the second case, your function obviously seems wrong.

Finally, in math an object does not "have a type" but "belongs to a set/class". For example, "1" is an integer, an odd number, a real, a complex, a scalar, a rank 1 tensor, etc... Saying that "1" is only an integer is incorrect, but that's what most programming language do.

I've tried to design a language where "typeof variable == type" does not exist but instead you have "variable isof type" running the type checking code, example:

  class user(v: struct {
    name: string,
    logged_in: bool
  })

  class logged_user(u: user) check
    # this code is evaluated when 'isof' is called
    u.logged_in = true
  end

  class allowed_user(u: user) check
    # =>,  operators are logical connectors
    # A => B is true if A and B are true or A is false
    # A  B is true if A and B are both true
    u isof logged_in  u.name in ['admin', 'root']
  end

  let alice = { name: 'alice', logged_in: false }
  assert alice isof user = true
  assert alice isof logged_user = false
  assert alice isof allowed_user = false

  let bob = { name: 'bob', logged_in: true }
  assert bob isof user = true
  assert bob isof logged_user = true
  assert bob isof allowed_user = false
But lazyness got the best of me and I only implemented the parser :(

Re: Rust's type system is Turing-complete (2017)

#33

Earlier quoted context omitted.

I disagree. A terminating type checker is much more valuable than a possibly non-terminating one. Also I think you're possibly conflating multiple issues here. Higher-kinded types, dependent types and kind polymorphism don't actually mean your type system becomes undecidable. They do vastly complicate the implementation in other ways, though.

It's easy enough to turn a non-terminating type checker into a terminating one, just add a recursion limit.

That makes it nearly impossible for the programmer to predict what will type check and what will not.

Re: Rust's type system is Turing-complete (2017)

#34
> Most if not all Turing-complete systems are also known to be Turing-equivalent. (I regret not being able to find a better citation for this.)

It links to Wikipedia (WP), which defines "system" by:

> a computational system (such as an abstract machine or programming language)

there is no better citation[0], because it's not true under some definitions of "computational system", per WP's definition of "computational system" [3]. For example, under the WP definition of "abstract machine", a non-computable function satisfies the definition. Or we can define it as follows: input: strings in an alphabet A, output: {true, false}, operations allowed: check for membership in a language L in alphabet A.

So we see that theoretical formal languages are a subset of computational systems. But there are uncountably many formal languages and only countably many TM. Crucially, we can easily turn each language into one that acts as a universal turing machine while still being distinct. Hence there are uncountably many Turing-complete languages for a given alphabet A[2]

[0]: incidentally, the linked WP page claims slightly differently (unimportantly) that "All known Turing-complete systems are Turing-equivalent, which adds support to the Church–Turing thesis."

[1]: "A typical abstract machine consists of a definition in terms of input, output, and the set of allowable operations used to turn the former into the latter." Absent a more precise definition, I assume the set may include arbitrary mathematical operations (and it is useful to define non-computable abstract machines, and in general usage in the field abstract machines may refer to languages more powerful than Turing machines).

[2]: Sketch: Let U' be a Universal TM in alphabet A (hence U is Turing-complete), let M' denote the language it accepts, and let 0 be a symbol of A. Define M such that if i' in M', then i in M, where i is i' with every symbol duplicated and 0 prefixed (hence if i'="123", i="0112233") Define N such that if i' in complement(M'), then i in N, where i is i' with every symbol duplicated and 0 prefixed. Observe that every language disjoint from N that contains M is Turing-complete (wrt a slightly modified description for TMs and the simulated input than the one for U'). Now, let L be an arbitrary language in A. Define f(L) = { j | j' in L, j is j' with every symbol duplicated }. Then we see that f(L), M, N are all disjoint. And if T, U are distinct languages, so (f(T) union M) and (f(U) union M) are distinct languages that simulate Turing machines (i.e. they are Turing-complete). Hence there are uncountably many Turing-complete languages. There are only countably many Turing machines, hence only countably many Turing-equivalent languages, so in fact most Turing-complete languages are not Turing-equivalent languages.

[3]: of course,

Re: Rust's type system is Turing-complete (2017)

#35
post #6

To me the main takeaway of results like this is: you're already paying the full price of using whatever complicated type system feature you care to name. So I have limited sympathy for people who are scared of the complexity of, say, higher-kinded types, or dependent types, or kind polymorphism. Your type system is already as complicated as possible, adding more features won't make it more Turing-complete - rather, m…

I disagree. A terminating type checker is much more valuable than a possibly non-terminating one. Also I think you're possibly conflating multiple issues here. Higher-kinded types, dependent types and kind polymorphism don't actually mean your type system becomes undecidable. They do vastly complicate the implementation in other ways, though.

> I disagree. A terminating type checker is much more valuable than a possibly non-terminating one.

I don't think that's true at all, and I think there are two extreme examples that drive the point home:

Consider on the one hand a language where typechecking is entirely terminating so long as you don't use one particular feature; however, that feature is also not very useful in practice (even notwithstanding the potential nontermination) and so it doesn't actually get used by real people writing real code. Adding that feature doesn't improve the language, but I contend that it doesn't make the type checker "much [less] valuable."

On the other hand, consider a language where type checking provably terminates in all cases, but based on subtleties sometimes completes in seconds and sometimes takes decades. I don't think this provides "much more [value]" than a similar system that sometimes fails to terminate only in some of the cases where the other would take (say) more than a week.

Re: Rust's type system is Turing-complete (2017)

#36

One of the reasons I like weak type systems or duck typing as is with vanilla JS is because I don't have cognitive overload... I don't have to think about abstractions as types I only need to think how to solve the problem in front of me. My unit tests can check for correctness after I've solved the problem. The fact that you can have Turing completeness in a type-system (not the language itself but within it's type…

I have the inverse experience. I find it far more cognitively burdensome to have to keep track of the types without annotations or assistance from a type checker. Getting rid of the type checker doesn’t make the type go away, it just means the full burden of managing them correctly falls on the programs. And it’s not for lack of effort—I’ve been using Python among other languages for 15 years, but I would still find…

I personally found Go far more unproductive than Python - doing if err!=nil a zillion times and writing the nth for loop..it made me cry worse than cutting fresh onions.

Python is not Perfect (bad general-purpose performance), but IMHO honestly a more productive language than Go.

And Python has type hinting nowadays which is sweet when you want it. Type hinting is good for self-documenting stable code.

Re: Rust's type system is Turing-complete (2017)

#37

> Most if not all Turing-complete systems are also known to be Turing-equivalent. (I regret not being able to find a better citation for this.) It links to Wikipedia (WP), which defines "system" by: > a computational system (such as an abstract machine or programming language) there is no better citation[0], because it's not true under some definitions of "computational system", per WP's definition of "computational…

Systems which are turing-complete but not turing-equivalent are stronger than turing machines. See: https://en.wikipedia.org/wiki/Hypercomputation

The "All known Turing-complete systems are Turing-equivalent, which adds support to the Church–Turing thesis." thing seems to have an implied "Turing-complete systems that are physically implementable." (I edited the article to add that.)

Re: Rust's type system is Turing-complete (2017)

#38

Earlier quoted context omitted.

It's easy enough to turn a non-terminating type checker into a terminating one, just add a recursion limit.

That makes it nearly impossible for the programmer to predict what will type check and what will not.

This isn't a problem at all for modern type systems. OCaml, Haskell, and even C++ have Turing complete type systems and this is one of the last concerns for developers.

Re: Rust's type system is Turing-complete (2017)

#39

Earlier quoted context omitted.

It's easy enough to turn a non-terminating type checker into a terminating one, just add a recursion limit.

That makes it nearly impossible for the programmer to predict what will type check and what will not.

for c++, I know both clang and gcc make the template resolution depth accessible to the developer via a compiler flag, allowing those that bypass the reasonable defaults to extend that depth.

Re: Rust's type system is Turing-complete (2017)

#40
The article is fascinating and I love fun stuff like this, but the discussion is a bit off the rails. There are a lot of things that are accidentally Turing complete. Turing complete is not synonymous with complicated and unwieldy to use. I mean, okay, maybe if you are doing the stuff that the author is doing it is complicated and unwieldy - in fact to the point that you would never do it in the first place. But Turing completeness is really not a high bar to reach.
Post reply on HN