> Turing-completeness is especially dangerous, and you want to avoid it if you don't actually need it.
Can I ask why Turing-completeness is "especially dangerous"?
Let's say we have a pure language for e.g. generating a JSON value (nested lists/maps of strings, floats, nulls and booleans). It has no primitives other than null, true/false, string, float, list, map and function literals, and corresponding "arithmetic" functions for each type.
What would the safety and security differences be between such a language being Turing-complete and not being Turing-complete?
Programs in these languages can't "do" anything, other than calculate. The only problem I can think of is making denial-of-service easier, by e.g. generating an infinitely large list and running out of memory:
(\x -> [ null ] ++ (x x)) (\x -> [ null ] ++ (x x))
This will generate `[ null, null, null, ... ]` until it runs out of memory. However, we could still blow the memory
without Turing-completeness, e.g. by growing an exponentially large datastructure for a large number of steps (basically like a zip bomb):
(\f xs -> case xs of
nil -> [ null ]
(cons y ys) -> (f f ys) ++ (f f ys))
(\f xs -> case xs of
nil -> [ null ]
(cons y ys) -> (f f ys) ++ (f f ys))
[ null, null, null, null, null, ...and so on 1000 times ]
This recursion is well-founded, and structurally-decreasing since we only call `f` with a strictly-decreasing value of `xs`, until we hit the base-case for `xs = nil` where we return `[ null ]`. In the non-base-case we recurse twice to generate two identical lists, then append them together. This results in a list with 2^1000 elements, easily consuming all available memory.
Hence for security, we need to kill programs which go over some predefined time/memory bounds regardless of whether or not they're Turing-complete. Hence my question about whether or not Turing-completeness is "especially dangerous", in comparison to e.g. I/O primitives.