HNHacker News
TopNewBestAskShowJobs

danidiaz

628 karma · joined December 22, 2012

productivedetour.blogspot.com
submissionscomments
danidiaz··on The rise of E Ink Tablets and Note Takers: reMarkable 2 vs Onyx Boox Note Air
This is one such setup: https://twitter.com/fresheyeball/status/1403192219092144130
danidiaz··on The Fixed Point: Laziness, Recursion and Fixed Points in Haskell
One practical use of "fix" is emulating Python-like decorators in Haskell: http://web.cecs.pdx.edu/~ntc2/haskell-decorator-paper.pdf

Fixed points are also an important part of the technique described in the paper "Abstracting Definitional Interpreters" https://arxiv.org/pdf/1707.04755.pdf

danidiaz··on Persian legends and their Western counterparts (2020)
I recently read and enjoyed "Haft Peykar" by the poet Nizami. Although I guess that much of its original beauty is lost in translation, some the language and imagery remain striking nonetheless.

One of the stories-within-the-story is the original source of Puccini's "Turandot".

https://en.wikipedia.org/wiki/Nizami_Ganjavi#Haft_Peykar

danidiaz··on Teeing, a hidden gem in the Java API
Here's a possible implementation of "duplicate": https://stackoverflow.com/a/67475265/1364288
danidiaz··on Teeing, a hidden gem in the Java API
I'm not sure you could implement a useful flatMap() for Collector-like types, at least without forcing the collector to hold all the received values in memory, which would defeat the purpose.

It would be like a function that takes

- a Collector that produces an X

- a function that takes an X and returns a Collector that produces an Y

and returns a Collector that produces an Y.

The thing is: while being fed, the result Collector should first feed the initial Collector and, at some time, "switch" to the Collector produced by the function. But when to perform the switch?

danidiaz··on Teeing, a hidden gem in the Java API
In Haskell terms, Collectors have an Applicative instance, and teeing corresponds to the liftA2 function:

> liftA2 :: (x -> y -> z) -> Fold a x -> Fold a y -> Fold a z

The "teeing" functionality is actually one of the "selling points" of the Collector-like library, not a hidden gem:

> This module provides efficient and streaming left folds that you can combine using Applicative style.

It's curious how the same abstraction can have different emphases across languages.

Collectors are also Comonads:

- You can always extract a value of the type that parameterizes the Collector, just by "closing" it.

> extract :: Fold a x -> x

- You could, in theory, "duplicate" a Collector<X> and get a Collector<Collector<X>>. This seems like a dumb function, but it would allow you for example to feed different Streams to the "same" collector, by duplicating it before consuming a Stream, the taking the result Collector, duplicating it again, passing it to another Stream...

> duplicate :: Fold a x -> Fold a (Fold a x)

http://hackage.haskell.org/package/foldl-1.4.11/docs/Control...

danidiaz··on State in Haskell (1995) [pdf]
I believe that negative view of do notation is not popular nowadays. The tendency is to lean more on it. There are language extensions like ApplicativeDo and the newer QualifiedDo which expand the reach of the notation.
danidiaz··on State in Haskell (1995) [pdf]
The paper notes a limitation this approach has with arrays: once you stop mutating an array and want to make a "pure" version that is useable outside ST, you have to choose between the safe but slow option of copying the array, and the true to its name "unsafeFreeze" function:

> The implementation of arrays is straightforward. The only complication lies with freezeArray, which takes a mutable array and returns a frozen, immutable copy. Often, though, we want to construct an array incrementally, and then freeze it, performing no further mutation on the mutable array. In this case it seems rather a waste to copy the entire array, only to discard the mutable version immediately thereafter.

> The right solution is to do a good enough job in the compiler to spot this special case. What we actually do at the moment is to provide a highly dangerous operation unsafeFreezeArray, whose type is the same as freezeArray, but which works without copying the mutable array. Frankly this is a hack, but since we only expect to use it in one or two critical pieces of the standard library, we couldn't work up enough steam to do the job properly just to handle these few occasions.

It seems that the recent addition of linear types to GHC 9.0 will enable "freeze" operations that are both fast and safe: http://hackage.haskell.org/package/linear-base http://hackage.haskell.org/package/linear-base-0.1.0/docs/Da...

danidiaz··on A Vim Guide for Advanced Users
> did not know you could do global marks with mA and `A.

Incidentally, the "Vimium" browser extension also supports those marks with the same syntax; they're an interesting alternative to conventional bookmarks for frequently accessed pages. https://github.com/philc/vimium/blob/master/README.md

danidiaz··on Mistakes to Avoid If You Work with Scala Futures
The error is explicitly awaiting for the result; "sending tasks" to the future is the correct way, and corresponds to "then" in Promise.
danidiaz··on Command Line Shell for SQLite
One annoyance is that on Windows the binary distribution of the shell doesn't support readline bindings. You have to recompile the shell for that. Instead of recompiling, I wrote a simplistic rlwrap clone in Haskell https://gist.github.com/danidiaz/97edc1bf248f5dce34aeb370363... which does the job.
danidiaz··on Mocks Aren't Stubs (2007)
The same "final state" of a fake can potentially be achieved by many different patterns of interaction between the system under test and the fake.

We don't really care about those patterns of interaction as long as they end up doing the right thing: allowing the SUT to affect his "outside world" as intended.

Making assertions about the exact pattern of interaction (that is: using mocks) is too high granularity, and will make the tests break on valid refactorings. Because we don't care about the pattern itself—it's just an implementation detail—but about what it achieves.

danidiaz··on Haskell is a Bad Programming Language (2020)
I disagree with this:

> One, types are a concretion. If you’re looking for higher level of abstractions to get flexible behaviour, you’re ultimately going to have a world of pain

I don't see why types should be in the way of flexible behaviour. Frameworks like Spring in Java use types to direct dependency injection and it works well.

Also this:

> Types wrap data and treat it like a black box whereas schema describes the shape and content of data.

Types can be made abstract and blackboxy, and sometimes that's what you want. But doesn't a record type give info about its fields? Doesn't a sum type give info about possible alternatives in the values?

> As such haskell ultimately suffers a lot when they have to interact with the real world. Suddenly they are left reeling as they find out that the real world is, in fact, dynamic.

The trick is to know what we are really modelling. If we are deserializing domain objects from JSON, it makes sense to have types for the domain objects. If we are writing a tool like, say, jq, perhaps we should merely have a datatype for the JSON tree itself: http://hackage.haskell.org/package/aeson-1.5.5.1/docs/Data-A...

> Bottom up design is something we’ve learnt collectively as a good way to be much more flexible in responding to change.

Even if you want to design bottom-up, the moment you want to add anything to your program, you need a little top-down thinking, if only at the micro-level. You want to create something new that isn't there, and then think how to accomplish that with the tools you have.

danidiaz··on GHC 9.0, supporting linear types
According to the proposal, affine types and linear types "are not equi-expressive": https://github.com/ghc-proposals/ghc-proposals/blob/master/p...
danidiaz··on John Carmack on Inlined Code (2014)
On the opposite end, reading long functions can be hard when they mix levels of abstraction, or their lack of abstraction buries the overall logic with details.

If I'm reading a novel, it would be jarring to read "and then he took 45 steps of average length to reach the kitchen" instead of "he went to the kitchen".

danidiaz··on Existential Haskell
With [a] -> b, when production of the input elements requires I/O and you don't want to read the entire list beforehand, you are forced to use lazy I/O, which is notoriously flaky and doesn't handle errors well.

Meanwhile, with a Collector, you can read the inputs with standard IO actions just fine, and feed them as they are produced.

danidiaz··on Existential Haskell
It's not isomorphic to [a] -> b, because you are not restricted to feed a Collector with a preexisting list, you can feed it with lines read incrementally from stdin for example.

Another difference is that you can combine a "Collector a b" and a "Collector a c" into a "Collector a (b,c)" that, like its components, only requires a single pass of the data. (This would be the Applicative instance for collectors.) Combining functions [a] -> b and [a] -> c doesn't necessarily "stream".

Also, I didn't use GADTs, only GADT "syntax" in which data constructors are provided as functions with signatures (MakeCollector :: ...)

Personally, I find this syntax much clearer for existential types. It amounts to having a type variable in a parameter which doesn't appear in the return type of the constructor.

danidiaz··on Existential Haskell
One neat and practical application of existential types if for defining "collectors" for streaming sources. The internal state of the collector is hidden and it can be different form what the collector ultimately returns. For example, a collector that returns the average of its inputs can store sum and count separately as its internal state. This also makes it easier to combine collectors.

In Haskell, using GADTSyntax, it would be something like

    data Collector a b where
        MakeCollector :: (x -> a -> x) -> x -> (x -> b) -> Collector a b
That is: to construct a collector that ingests as and returns a single b, you need to supply a step function, the initial state of type x, and a "tally" function that calculates the result b from the final state. The type of the state ("x") is not present in the type "Collector a b"; it is an "existential".

In the Java Collectors framework, this is (roughly) analogous to

    Collector.of (Supplier<A> supplier, BiConsumer<A, T> accumulator, BinaryOperator<A> combiner, Function<A, R> finisher, Collector.Characteristics... characteristics)
And the type parameter that corresponds to the existential in Haskell is:

    A - the mutable accumulation type of the reduction operation (often hidden as an implementation detail)
danidiaz··on Pure destination-passing style in Linear Haskell
The only way to get hold of a DArray is inside the callback of the "alloc" function:

     alloc :: Int -> (DArray a ⊸ ()) ⊸ Array a
According to the linear Haskell paper: "f :: s ⊸ t guarantees that if (f u) is consumed exactly once, then the argument u is consumed exactly once." Also: "To consume a pair exactly once, pattern-match on it, and consume each component exactly once"

So, if we call splitDArray inside that callback, then we are obliged to consume each of the resulting (DArray a, DArray a) exactly once to satisfy the constraint that the input is consumed exactly once.

danidiaz··on Real World Haskell
This is a good way of getting your feet wet: https://haskell-via-sokoban.nomeata.de/
danidiaz··on Switching from Vim to Intellij
This post might give some ideas about configuring .ideavimrc https://medium.com/@danidiaz/configuring-ideavimrc-de16a4da0... Although one person's finely honed vimrc is another's absurd unergonomic configuration.
danidiaz··on Haskell GHC 9.0.1-alpha
Besides potentially enabling new types of APIs, I simply like that this extension lets you write more precise type signatures. A function with type [a] %1 -> [a] can do less things that a function with type [a] -> [a].
danidiaz··on OOP: History, and challenges for the next fifty years (2013)
There are indeed "coalgebraic" descriptions of OOP.

- "Objects and Classes, Coalgebraically" (1995) http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.29.6...

- "Codata in action" (2019) https://www.microsoft.com/en-us/research/publication/codata-...

Coalgebras fit very well with the "hidden internal state" that characterizes objects in OOP.

danidiaz··on The Universe Knows Right from Wrong
Bart Streumer is mentioned in the piece. His book "Unbelievable Errors: An Error Theory about All Normative Judgements" begins with a pretty cool sentence:

> You cannot believe the view I will defend in this book. I therefore will not be able to convince you that this view is true.

danidiaz··on Read Fewer Books
> Strikingly, the most intelligent and thoughtful intellectual of the early church seems to have read fewer things than an average modern eight year old. To follow the depiction by Antonello da Messina, St Jerome appears to be the proud owner of about ten books in all!

What is a painting from 1475 supposed to tell us about the reading habits of the real St. Jerome, patron saint of librarians?

The paper "A History of Early Christian Libraries from Jesus to Jerome" by Thomas M. Tanner looks like a good source of information on the subject, but sadly it's only available from JSTOR.

danidiaz··on Haskell Mini-Patterns Handbook
Phantom types can be useful when modelling currency: the "implementation" stays the same but you want to avoid summing two different currencies by mistake.

https://ren.zone/articles/safe-money

danidiaz··on The Pandemic-Era Appeal of Labyrinths
In Antiquity and the Middle Ages, there was something of an incongruence between literary and visual depictions of labyrinths ("The Idea of the Labyrinth" touches on this). In literary sources, the labyrinths were often "multicursal", like mazes. One can choose a wrong turn and get lost. The labyrinth at Crete is described like that. But graphical depictions are almost invariably "unicursal" for some reason.

From Wikipedia: https://en.wikipedia.org/wiki/Labyrinth

"Although early Cretan coins occasionally exhibit branching (multicursal) patterns,[2] the single-path (unicursal) seven-course "Classical" design without branching or dead ends became associated with the Labyrinth on coins as early as 430 BC,[3] and similar non-branching patterns became widely used as visual representations of the Labyrinth – even though both logic and literary descriptions make it clear that the Minotaur was trapped in a complex branching maze."

If the cretan Labyrinth didn't have branching paths, why would Theseus need a ball of thread to retrace his steps? https://en.wikipedia.org/wiki/Ariadne#Minos_and_Theseus

danidiaz··on The Pandemic-Era Appeal of Labyrinths
An interesting (and free) book about the subject is "The Idea of the Labyrinth from Classical Antiquity through the Middle Ages" by Penelope Reed Doob https://www.amazon.com/Labyrinth-Classical-Antiquity-through... Sometimes it goes too far in seeing a "labyrinthine aesthetic" everywhere, but nevertheless it contains interesting information.

Speaking of labyrinths, programmers are like Daedalus: they design labyrinths, only to be immured inside them. Daedalus was commissioned to build an actual labyrinth; programmers set out to build cathedrals, but then mess up. They keep reworking sections of the labyrinth even as they are lost inside, trying to straighten out the paths, render them comprehensible. But they always end up creating more twists and turns.

danidiaz··on Bitoduc: A French dictionnary for CS related words
I like that in French, instead of collecting garbage, you collect bread crumbs: "ramasse-miettes"

Also, in German, earlier software versions are located downwards, not backwards: "Abwärtskompatibilität"

danidiaz··on 50 authors, 50 science fiction stories shorter than novels
One interesting collection of science fiction short stories from the early seventies is "Moderan" by David R. Bunch. After many years out of print, it was recently re-published in the NYRB Classics series: https://www.goodreads.com/book/show/38732324-moderan Very surreal—and sometimes disturbing—tales about cyborgs trying to leave their humanity behind.

Another masterful writer of surreal science fiction stories was R. A. Lafferty https://www.amazon.com/Best-R-Lafferty/dp/1473213444/

← PreviousPage 2 of 9Next →