yoneda
> Obviously, λx.M should be seen as a sort of function
The fact that lambdas can be seen as a syntax for describing functions (or function-like things) is kind of obvious to anyone who knows basic programming language theory (and many software engineers who use lambdas when they map over a list, for example).
The sentence before it about β-reduction is describing the rule for how to call a function, which we learned in high school as "plug-and-chug".
I think the confusion here might just be that the syntax is unfamiliar. You have probably seen these concepts before.
These are good ideas for sure, but they are bread and butter to anyone who is familiar with functional programming. The Lisp and ML families of languages have had them for many decades.
The fact that more languages _aren't_ like this is what's surprising to me, given how effective they are. I love that Rust is bringing them to the masses, but what on earth took the industry so long to accept them?
I guess the answer is that algebraic data types (inductively defined data) tend to be pitted against object-oriented programming (coinductively defined data), and object-oriented programming has dominated the industry for the past 3 decades. Some languages like Kotlin have tried to combine them, but personally I'd rather just embrace the former and relegate the latter to a seldomly-used design pattern, not a programming paradigm hardcoded into the language.
Under the hood, of course, they are implemented with C-style unions with fields sharing memory. But to conflate Rust's enums with how they are implemented is to disregard the extra safety that they provide.
No, you're mixing up concepts (consistency vs. soundness).
If a type system has non-normalizing types (or non-normalizing terms which appear in types), then it is inconsistent as a logic, which means that via Curry-Howard you can prove anything (ex falso quodlibet). Regarding incompleteness, any sufficiently expressive logic is incomplete per Gödel's first incompleteness theorem.
A type system which is inconsistent as a logic can still be sound as a type system. Soundness is the property that you described in your second paragraph (not letting "invalid" programs through). A simple example is System U. It's sound as a type system, but inconsistent as a logic. That means it works for programming, but not for proving.
I found this article really helpful for explaining why laziness is important: http://augustss.blogspot.com/2011/05/more-points-for-lazy-ev...
In particular, scroll down to the "Reuse" section. Lazy evaluation enables you to compose functions to build new functions with the right performance characteristics (constant factors aside), as in:
any :: (a -> Bool) -> [a] -> Bool
any p = or . map p
In an eager language, predicate `p` would have to be evaluated on every element in the list, even if the predicate is already satisfied after the first element. So instead you'd have to write this function in an ad hoc way with explicit recursion/looping, without being able to reuse the more primitive functions.Of course, in an impure language, laziness can't be the default because you wouldn't be able to reason about when your side effects occur. But in my mind that's an argument for purity rather than an argument for eagerness.
BTW, comparing "strict" vs. "lazy" is a category error. The proper comparison would be either "strict" vs. "non-strict" or "eager" vs. "lazy". The former is in reference to the denotational semantics, whereas the latter characterizes the operational semantics.
That's not what proof assistants like Lean and Coq are about. Sure, they can automate some trivial things, but generally their main utility is that they check your reasoning, not come up with it for you.