HNHacker News
TopNewBestAskShowJobs

one-punch

237 karma · joined August 25, 2019

Be to the point.
submissionscomments
one-punch··on Names are not type safety
For those who may not be familiar with the Haskell ecosystem, Alexis King (lexi-lambda) writes many blogs and libraries related to Haskell.

For example, you may be interested in her recent talk on effect systems in Haskell at ZuriHac 2020,[1] based on the eff library she mainly contributes to.[2]

[1]: https://www.youtube.com/watch?v=0jI-AlWEwYI

[2]: https://github.com/hasura/eff

> he's asking you to read the article more carefully

she

one-punch··on Generalizing 'jq' and Traversal Systems using optics and standard monads
For me, the remaining power of optics (what you call 20%):

1. let the compiler reason about my code to catch errors when the requirement changes (say, when some record fields change their names or types),

2. thus lower my cognitive load, and

3. allow me to reason about more important aspects of the project.

At work, the use of a powerful and expressive type system allowed me to work on multiple projects at once, achieving at least 2 times boost in productivity (definitely more than 20% gain).

Moreover, if optics is not well-known to everyone, I can just link to this blog post as a documentation, and give more examples if needed (I think people underestimate how coworkers could be productive without completely understanding everything).

It is hard to explain the experience of “pair-programming with the compiler”, but such complication is worthwhile for the productivity gain (and developer happiness).

one-punch··on The unreasonable effectiveness of declarative programming
I believe this library would be very useful for simple animations. The small size and simple API should make this usable in many cases.

As for more sophisticated animations, I can think of reanimate [1], which outputs animations in SVGs, and should work on the web with wasm if integration is needed [2][3].

I completely agree that declarative programming (and functional-style programming) shines for composing animations. Imperative programming does not show the intent as clearly, and makes it hard to reason about or time travel animations.

[1]: https://reanimate.readthedocs.io/en/latest/glue_tut/

[2]: https://github.com/tweag/asterius

[3]: https://github.com/Lemmih/reanimate

one-punch··on What if we'd had better HTML-in-JS syntax all along?
It produces structured data (the `MarkupM` datatype from `blaze` to be precise [1]).

To check this, note that Hamlet produces `Html` [2], which (when following the link) is defined to be `Markup` [3], which is in turn `MarkupM` [4].

[1]: https://hackage.haskell.org/package/blaze-markup-0.8.2.3/doc...

[2]: https://hackage.haskell.org/package/shakespeare-2.0.24/docs/...

[3]: https://hackage.haskell.org/package/shakespeare-2.0.24/docs/...

[4]: https://hackage.haskell.org/package/blaze-markup-0.8.2.3/doc...

one-punch··on What if we'd had better HTML-in-JS syntax all along?
Reminds me of the “Shakespearean Templates“ [1] from the Yesod web framework [2].

[1]: https://www.oreilly.com/library/view/developing-web-applicat...

[2]: https://www.yesodweb.com/

Copied below to save you a click:

Hamlet (HTML)

    $doctype 5
    <html>
        <head>
            <title>#{pageTitle} - My Site
            <link rel=stylesheet href=@{Stylesheet}>
        <body>
            <h1 .page-title>#{pageTitle}
            <p>Here is a list of your friends:
            $if null friends
                <p>Sorry, I lied, you don't have any friends.
            $else
                <ul>
                    $forall Friend name age <- friends
                        <li>#{name} (#{age} years old)
            <footer>^{copyright}
Cassius (CSS)

    #myid
        color: #{red}
        font-size: #{bodyFontSize}
    foo bar baz
        background-image: url(@{MyBackgroundR})
Lucius (CSS)

    section.blog {
        padding: 1em;
        border: 1px solid #000;
        h1 {
            color: #{headingColor};
        }
    }
Julius (JavaScript)

    $(function(){
        $("section.#{sectionClass}").hide();
        $("#mybutton").click(function(){document.location = "@{SomeRouteR}";});
        ^{addBling}
    });
For those curious, the above is implemented in the metaprogramming framework of Template Haskell.
one-punch··on Arduino-copilot makes it easy to use Haskell to program an Arduino
The code is mostly pure Haskell (the do block, which most Haskellers are familiar with), with a few domain-specific elements (those led and delay “assignments” and the Stream type in this functional reactive programming framework arduino-copilot, whose meaning is specific to this Arduino application and most Haskellers have to guess).

The short answer is that I could guess what it means.

This `arduino-copilot` example really showcases one killer application of Haskell: writing eDSL (embedded domain-specific language) in Haskell.

Haskell allows really high level abstraction: in particular, you can overload the operator which combines different statements in Haskell. In C/C++, the semicolon combines subsequent statements, Haskell even allows you to overload (give a new meaning to) the semicolon “operator” (think of overloading ; instead of overloading +). That is, in Haskell we can interpret differently how to combine subsequent statements in different contexts (such as null-checking, exception handling, async/await style concurrency, looping, or procedural state passing, etc., see the example below).

However, when we “overload the semicolon operator”, we intuitively have some expectations:

1. We expect to be able to turn a value into a standalone statement (to inject a value as a single statement with that value, e.g., to turn the value “97” into the statement “97;”, and this operation is called return)

2. We expect to be able to use the result of a statement in the next statement as in

    str <- getLine;
    putStrLn str
This could be rewritten using a bind operation (denoted >>=) as getLine >>= putStrLn.

When we package up (encapsulate) the above two operations (return and bind), we expect the two operations to play nicely with each other to satisfy some intuitive laws (e.g,. if you inject a value then use the value in a subsequent functional statement, it is the same as just calling the function on the value, so the return and bind cancels out, etc.). A mathematical formalization of this idea (the two operations with some intuitive laws) is named a monad, which happens to generalize many different computational contexts of combining statements such as null-checking, exception handling, async/await style concurrency, looping, or procedural state passing [1].

[1]: https://philipnilsson.github.io/Badness10k/posts/2017-05-07-...

The ability to reinterpret statement compositions is why Haskell is so great for embedding domain-specific languages (even procedural eDSL), as the arduino article shows, and this is why some people call Haskell the finest procedural language.

one-punch··on Arduino-copilot makes it easy to use Haskell to program an Arduino
My understanding is that the domain-specific language (which is embedded in Haskell) generates C code, which is then compiled to an arduino binary.

The key sentence:

> This whole example turns into just 63 lines of C code, which compiles to a 1248 byte binary, so there's plenty of room left for larger, more complex programs.

What the eDSL (embedded domain-specific language) offers is a higher level of abstraction: by using functional reactive programming, the programmer can reason about the code at a more intuitive level (instead of C, assembly, or machine code).

Usually people call this style of programming declarative instead of imperative: focusing on what to do instead of how to do it.

In a more interesting example in the article, we see right away that the LED is on when, and only when, the button is pressed or when it is “blinking”, with “a longer and longer” delay (with lower level details deferred to the counter function, or with the timing logic handled by the functional reactive programming framework—to appreciate the abstraction ability of FRP, try to imagine how to implement the same LED (which is on when pressed or with a longer and longer delay) in other procedural languages, likely different concerns will be interleaved).

When concerns are cleanly separated in Haskell, we understand what the code intends to do right away, making the code more maintainable. (And more fun to read and write!)

As a side bonus, Haskell has a strong and expressive type system, and a pervasive use of laziness to enable purity, allowing local equational reasoning (e.g., no need to worry about hidden mutable global state, so functions could be understood on their own, etc.), making the code even easier to reason about and to maintain then some other procedural languages (what you write is what you intuitively mean).

So I think the trade off is between developer productivity and performance (of the generated C code vs a handcrafted C code; very much like the trade off between a compiled machine code vs a handcrafted machine code).

one-punch··on Things I Learnt from a Senior Software Engineer
There is a cute name for, er, the two ways of naming systems: pets naming vs cattle naming [1]. I think naming after services is like pet naming, while naming them by numbers is like cattle naming.

Pets Service Model

In the pets service model, each pet server is given a loving names like zeus, ares, hades, poseidon, and athena. They are “unique, lovingly hand-raised, and cared for, and when they get sick, you nurse them back to health”. You scale these up by making them bigger, and when they are unavailable, everyone notices.

Examples of pet servers include mainframes, solitary servers, load balancers and firewalls, database systems, and so on. Cattle Service Model

In the cattle service model, the servers are given identification numbers like web-01, web-02, web-03, web-04, and web-05, much the same way cattle are given numbers tagged to their ear. Each server is “almost identical to each other” and “when one gets sick, you replace it with another one”. You scale these by creating more of them, and when one is unavailable, no one notices.

Examples of cattle servers include web server arrays, no-sql clusters, queuing cluster, search cluster, caching reverse proxy cluster, multi-master datastores like Cassandra, big-data cluster solutions, and so on.

[1] https://medium.com/@Joachim8675309/devops-concepts-pets-vs-c...

← PreviousPage 3 of 3