<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Hacker News: catnaroek</title><link>https://news.ycombinator.com/user?id=catnaroek</link><description>Hacker News RSS</description><docs>https://hnrss.org/</docs><generator>hnrss v2.1.1</generator><lastBuildDate>Tue, 08 Sep 2026 18:48:25 +0000</lastBuildDate><atom:link href="https://hnrss.org/user?id=catnaroek" rel="self" type="application/rss+xml"></atom:link><item><title><![CDATA[New comment by catnaroek in "Strongly Typed Heterogeneous Collections (2004) [pdf]"]]></title><description><![CDATA[
<p>Calling HLists “collections” is misleading. In spite of their name, HLists are actually record types. The only actual list involved is a compile-time list of component types used to form a record type.<p>To give a perhaps odious but relatable analogy, a form is a list of questions, but a filled form is not a list of answers - it is a record of answers to the questions in the form.</p>
]]></description><pubDate>Mon, 17 Sep 2018 23:32:49 +0000</pubDate><link>https://news.ycombinator.com/item?id=18011037</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=18011037</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=18011037</guid></item><item><title><![CDATA[New comment by catnaroek in "Getting specific about generics"]]></title><description><![CDATA[
<p>In general, Haskell does not do parametric polymorphism through monomorphization. In particular, higher-rank polymorphism becomes unusable if polymorphism is implemented through monomorphization. On the other hand, if I recall correctly, Rust only supports higher-rank polymorphism for lifetimes, which neither have nor need a runtime representation. This is why monomorphization is a viable implementation strategy for Rust generics.<p>(Aside: Type checkers essentially see recursive function definitions as applications of a fixed point operator to non-recursive functions. If your function has a rank-1 type but uses polymorphic recursion, the type checker sees it as the application of a rank-2 fixed point operator to a non-recursive function. This is why I see polymorphic recursion as “morally higher-rank polymorphism”, even when the type signatures in your code are ostensibly rank-1 ones. Polymorphic recursion is widely used in Haskell.)<p>However, IMO, you only need rank-1 polymorphism 95% of the time anyway, so optimizing for the common use case is a good strategy. By far, the main use case for generics is implementing efficient and reasonably reusable data structures and algorithms in a reasonably type-safe way. For this use case, monomorphization and aggressive inlining of small functions are evidently the right things to do. Other uses of generics (say, streaming I/O frameworks) strike me as a lot more questionable.</p>
]]></description><pubDate>Sun, 09 Sep 2018 18:22:58 +0000</pubDate><link>https://news.ycombinator.com/item?id=17947083</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=17947083</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=17947083</guid></item><item><title><![CDATA[New comment by catnaroek in "Program Induction and Synthesis at ICML 18"]]></title><description><![CDATA[
<p>Two words: loop invariant. Implement a system that figures out the right loop invariant given a problem description (expressed however you want), and you will have made a lot of progress.</p>
]]></description><pubDate>Fri, 17 Aug 2018 10:37:24 +0000</pubDate><link>https://news.ycombinator.com/item?id=17781730</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=17781730</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=17781730</guid></item><item><title><![CDATA[New comment by catnaroek in "Pyre: Fast Type Checking for Python"]]></title><description><![CDATA[
<p>That's actually Brian Kernighan. Dijkstra would have never advocated debugging to begin with.</p>
]]></description><pubDate>Fri, 18 May 2018 23:55:45 +0000</pubDate><link>https://news.ycombinator.com/item?id=17105815</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=17105815</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=17105815</guid></item><item><title><![CDATA[New comment by catnaroek in "Common Lisp homepage"]]></title><description><![CDATA[
<p>Oops, sorry, yes.</p>
]]></description><pubDate>Fri, 11 May 2018 23:46:45 +0000</pubDate><link>https://news.ycombinator.com/item?id=17051533</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=17051533</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=17051533</guid></item><item><title><![CDATA[New comment by catnaroek in "The Logical Disaster of Null"]]></title><description><![CDATA[
<p>Optionals are a better alternative to null. They compose better (i.e., they nest) and play nicely with data abstraction (i.e., you can define an abstract type that hides the fact that its underlying representation is optional), unlike null.</p>
]]></description><pubDate>Thu, 10 May 2018 13:18:37 +0000</pubDate><link>https://news.ycombinator.com/item?id=17038556</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=17038556</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=17038556</guid></item><item><title><![CDATA[New comment by catnaroek in "Common Lisp homepage"]]></title><description><![CDATA[
<p>Typed Racket is more ambitious than other attempts at adding types to an underlying untyped language. Namely, Typed Racket guarantees that typed code is never to blame for certain contract violations, and, if any such contract violation happens, it will be properly traced back to an offending piece of untyped code. This is what makes gradual types gradual (as opposed to merely optional), alas, it is also what has been found to have unacceptable overhead.<p>Relevant paper and talk:<p><a href="http://www.ccis.northeastern.edu/home/types/publications/gradual-dead/pre-treatment.pdf" rel="nofollow">http://www.ccis.northeastern.edu/home/types/publications/gra...</a><p><a href="https://www.youtube.com/watch?v=1u1JGwmW0IQ" rel="nofollow">https://www.youtube.com/watch?v=1u1JGwmW0IQ</a></p>
]]></description><pubDate>Thu, 10 May 2018 13:09:10 +0000</pubDate><link>https://news.ycombinator.com/item?id=17038495</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=17038495</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=17038495</guid></item><item><title><![CDATA[New comment by catnaroek in "Programming Language Theory in Agda"]]></title><description><![CDATA[
<p>> It doesn't try to analyze and compare existing programming languages.<p>It does. For example, this theory identifies when and how incorrectly designed programming languages fail to enforce abstractions, very much like how the theory of database normalization identifies when and how incorrectly designed database schemata fail to enforce data integrity constraints.<p>But perhaps what you mean is “it doesn't try to view existing programming languages under an unwarranted positive light”.</p>
]]></description><pubDate>Sat, 05 May 2018 03:25:12 +0000</pubDate><link>https://news.ycombinator.com/item?id=17000164</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=17000164</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=17000164</guid></item><item><title><![CDATA[New comment by catnaroek in "Differentiable Programming: A Semantics Perspective"]]></title><description><![CDATA[
<p>I don't understand in what sense programs can be called “differentiable”. Is the space of programs modulo observational equivalence a manifold to begin with? (I don't think it's Hausdorff or even T1, but I could be wrong.)<p>The examples given in the article are merely derivatives of ordinary mathematical functions defined by ordinary mathematical expressions - in particular, there are no sequencing, no conditionals and no loops. So why call them “differentiable programs” when you are actually dealing with ordinary differentiable functions from good old 19th century analysis? We need urgent improvements in the intellectual honesty department.</p>
]]></description><pubDate>Thu, 03 May 2018 12:41:31 +0000</pubDate><link>https://news.ycombinator.com/item?id=16985410</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=16985410</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=16985410</guid></item><item><title><![CDATA[New comment by catnaroek in "Eul – The language"]]></title><description><![CDATA[
<p>> Safety<p>> Variables are immutable by default, globals are not allowed, functions are pure.<p>This is a huge non-sequitur.</p>
]]></description><pubDate>Wed, 02 May 2018 20:44:05 +0000</pubDate><link>https://news.ycombinator.com/item?id=16980980</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=16980980</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=16980980</guid></item><item><title><![CDATA[New comment by catnaroek in "The Challenge of Cross-Language Interoperability (2013)"]]></title><description><![CDATA[
<p>You are badly conflating some issues here. How to implement automatic <i>memory</i> management is a runtime design issue. How to enforce proper <i>non-memory</i> resource management is a language design issue. Nothing forbids an implementation of a safe-Rust-like language with a garbage collector. Destructors would still be called deterministically, and destructed objects would still be unusable afterwards, as mandated by the language's semantics. But memory will only be reclaimed during the next garbage collection cycle.<p>There are other (better!) reasons against cross-language interoperability, though, such as the reduction in static guarantees to an unusable lowest common denominator.</p>
]]></description><pubDate>Wed, 02 May 2018 16:17:39 +0000</pubDate><link>https://news.ycombinator.com/item?id=16978478</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=16978478</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=16978478</guid></item><item><title><![CDATA[New comment by catnaroek in "Towards λ-calculus"]]></title><description><![CDATA[
<p>> The problem is, functional programming languages are almost always harder to read than other languages. Haskell is the obvious example<p>There are many legitimate reasons to dislike Haskell, such as being hard to parse mechanically, but being hard to read is not one of them.<p>> F# and other languages ML-style syntax are probably the easiest to read.<p>The syntax of ML's module language is pretty complicated. You cannot look at those “where type” (SML) and “with type” (OCaml) clauses and tell me with a straight face that they were meant to be easy to read. This syntax makes translucent ascription harder to read than it ought to be. It is so bad that many[0] people work around it in various ways, like using the combination of generative datatypes and transparent ascription as a poor man's translucent ascription.<p>As for F#, I would not call it ML-style, precisely due to the inability to express modular abstraction.<p>[0] Relative to the size of the ML community, of course.</p>
]]></description><pubDate>Wed, 02 May 2018 12:57:12 +0000</pubDate><link>https://news.ycombinator.com/item?id=16976416</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=16976416</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=16976416</guid></item><item><title><![CDATA[New comment by catnaroek in "Implementing and Understanding Type Classes (2014)"]]></title><description><![CDATA[
<p>I don't see anything wrong with rose trees:<p><pre><code>    datatype 'a tree = T of 'a * 'a tree list
</code></pre>
Do you?</p>
]]></description><pubDate>Sat, 28 Apr 2018 20:50:01 +0000</pubDate><link>https://news.ycombinator.com/item?id=16949351</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=16949351</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=16949351</guid></item><item><title><![CDATA[New comment by catnaroek in "Implementing and Understanding Type Classes (2014)"]]></title><description><![CDATA[
<p>Not too long was it figured out how to reconcile subtyping with type inference. However, this requires doing subtyping  in a very specific way, which most users of languages with subtyping will not find pleasing. In particular, the design of the type system must pay very close attention to issues of polarity and existence of certain universal objects in the categories of types. This work caters more to designers and users of ML-style languages who want to add subtyping, than to designers and users of more traditional languages who want to add type inference.<p><a href="https://news.ycombinator.com/item?id=13781467" rel="nofollow">https://news.ycombinator.com/item?id=13781467</a></p>
]]></description><pubDate>Sat, 28 Apr 2018 20:40:59 +0000</pubDate><link>https://news.ycombinator.com/item?id=16949314</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=16949314</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=16949314</guid></item><item><title><![CDATA[New comment by catnaroek in "Notes on structured concurrency, or: Go statement considered harmful"]]></title><description><![CDATA[
<p>Lately, I am of the idea that the real problem with how we do concurrency is that we have yet to figure out a way to do it without first-class procedures. When we spawn a thread, even in a low language such as C, we use something to the effect of:<p><pre><code>    launch_thread(function, perhaps, some, initial, data);
</code></pre>
The trouble with this approach to concurrency is twofold:<p>(0) It forces a hierarchical structure where one continuation of the branching point is deemed the “parent” and the others are deemed the “children”. In particular, if the forking procedure was called by another, only the “parent” continuation may return to the caller. This is unnatural and unnecessarily limiting. Even if you have valid reasons to guarantee that only one continuation will yield control back to the caller (e.g., to enforce linear usage of the caller's resources), the responsibility to yield back to the caller is in itself as a resource like any other, whose usage can be “negotiated” between the continuations.<p>(1) It brings the complication of first-class procedures when it is often not needed. From a low-level, operational point of view, all you need is the ability to jump to two (or more) places at once, i.e., a multigoto. There is no reason to require each continuation to have a separate lexical scope, which, in my example above, one has to work around by passing “perhaps some local data” to `launch_Thread`. There is also no reason to make “children” continuations first-class objects. If you need to pass around the procedure used to launch a thread between very remote parts of your program, chances are your program's design is completely broken anyway. These things distract the programmer from the central problem in concurrent programming, namely, how to coordinate resource usage by continuations.</p>
]]></description><pubDate>Wed, 25 Apr 2018 20:53:13 +0000</pubDate><link>https://news.ycombinator.com/item?id=16926030</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=16926030</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=16926030</guid></item><item><title><![CDATA[New comment by catnaroek in "Java is Pass-by-Value"]]></title><description><![CDATA[
<p>> Java's semantics are pass-by-value only of you consider that the "values" that are being passed are pointers.<p>All values in Java are indeed either primitives or pointers. You cannot define your own values! How is anyone supposed to call this a high-level language?</p>
]]></description><pubDate>Sun, 22 Apr 2018 18:02:29 +0000</pubDate><link>https://news.ycombinator.com/item?id=16897474</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=16897474</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=16897474</guid></item><item><title><![CDATA[New comment by catnaroek in "Building Robust Systems (2008) [pdf]"]]></title><description><![CDATA[
<p>> However, I am considering an even more general scheme, where it is possible to define what is meant by addition, multiplication, etc., for new datatypes unimagined by the language designer<p>So, um, like this?<p><pre><code>    signature RING =
    sig
      type t
      val + : t * t -> t
      val * : t * t -> t
      val ~ : t -> t
    end
</code></pre>
> Extensible generic operations are not for the faint of heart. The ability to extend operators after the fact gives both extreme flexibility and ways to make whole new classes of bugs!<p>This is <i>precisely</i> why parametric polymorphism is superior to ad-hoc polymorphism as a way to enable programs to work in previously unanticipated situations. Don't work with concrete use cases, work with the minimum abstract requirements that allow your program to work!<p>> On the other hand, some mutations will be extremely valuable. For example, it is possible to extend arithmetic to symbolic quantities.<p>So, for example, like this?<p><pre><code>    functor PolynomialRing (R : RING) : RING =
    struct
      type t = R.t list
      
      fun xs + nil = xs
        | nil + ys = ys
        | (x :: xs) + (y :: ys) = R.+ (x, y) :: xs + ys
      
      (* define multiplication and negation too... *)
    end</code></pre></p>
]]></description><pubDate>Sat, 21 Apr 2018 13:53:15 +0000</pubDate><link>https://news.ycombinator.com/item?id=16891417</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=16891417</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=16891417</guid></item><item><title><![CDATA[New comment by catnaroek in "Rust Formal Verification Working Group"]]></title><description><![CDATA[
<p>With mere “guidelines”, there is no practical, unambiguous way to establish without a shadow of doubt that a function implemented using unsafe Rust upholds the safety guarantees of safe Rust.<p>So I want a proper formal semantics, maybe not for all of Rust, but at least for a fragment interesting enough to express lifetime and mutability concerns. In particular, I want a formal account of interior mutability.</p>
]]></description><pubDate>Tue, 10 Apr 2018 03:05:13 +0000</pubDate><link>https://news.ycombinator.com/item?id=16798711</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=16798711</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=16798711</guid></item><item><title><![CDATA[New comment by catnaroek in "Rust Formal Verification Working Group"]]></title><description><![CDATA[
<p>Will there ever be a formal semantics for unsafe Rust?</p>
]]></description><pubDate>Mon, 09 Apr 2018 23:43:44 +0000</pubDate><link>https://news.ycombinator.com/item?id=16797934</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=16797934</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=16797934</guid></item><item><title><![CDATA[New comment by catnaroek in "Wizard for Mac – new kind of statistics program"]]></title><description><![CDATA[
<p>> Heck, R isn't really that accessible to most programmers either.<p>R is objectively a bad programming language. However, it is by no means inaccessible. I have no statistics background whatsoever, and I managed to learn enough R to be dangerous in a mere week. Other than the 1-based indexing and the utterly disgusting dynamic dispatch mechanism (you could simply not to use the latter), R is surprisingly pleasant to use. What I enjoyed the most is that vectors and matrices are first-class values, not objects that are referred to through pointers. It's probably copy-on-write under the hood, but I don't need to care. Hallelujah!</p>
]]></description><pubDate>Sun, 08 Apr 2018 03:04:11 +0000</pubDate><link>https://news.ycombinator.com/item?id=16784399</link><dc:creator>catnaroek</dc:creator><comments>https://news.ycombinator.com/item?id=16784399</comments><guid isPermaLink="false">https://news.ycombinator.com/item?id=16784399</guid></item></channel></rss>