HNHacker News
TopNewBestAskShowJobs

juxtapose

210 karma · joined August 11, 2020

submissionscomments
juxtapose··on How did you choose between Joplin, Foam, Trilium, Obsidian, Logseq, Roam?
I use Logseq because it is just a local-first version of Roam Research.

To those who haven't used Roam Research or Logseq or anything similar, you are missing some really good stuff.

juxtapose··on Ask HN: What technology is “cutting edge” in 2022?
For programming languages, dependent types.

DT is a hot topic in the PL community recently. It massively enhances the capability of a type system by turning it into a comprehensive logic system, so you can encode whatever properties you'd like to enforce into a type signature. Theorem provers have been taking advantage of the Curry-Howard correspondence for some time, but the implication of DT on real-world programming is still not well understood (we need more real-world projects written in DT languages). There are also ambitious projects that want to bring DT into the mainstream.

If you are interested, you can take a look at Lean [1], Idris [2], and a few others [3,4]. Often these languages have esoteric syntax, but there are projects using a more conventional syntax, too, e.g. Cicada [5]. "The Little Typer" [6] is a pretty good introduction to this topic.

[1] https://leanprover.github.io [2] https://www.idris-lang.org [3] https://github.com/agda/agda [4] https://coq.inria.fr [5] https://cicada-lang.org [6] https://mitpress.mit.edu/books/little-typer

juxtapose··on Features of a dream programming language
It's not hard to describe what monads are, but it's probably not going to convince anyone of its importance without an appropriate language. The monad per se is an extremely simple idea. In fact, monadic interfaces are ubiquitous:

    Rust:  Result::and_then()
    Scala: Option.flatMap()
    JS:    Promise.then()
    ...
I agree it can take some time to discover the similarities between these interfaces. But a monad is just that. It's so simple that we are blind to see.

Unfortunately, it requires a sufficiently advanced language to express the concept of Monad. You need at least higher-kinded types and means to describe behaviors of HKTs.

Can you understand or describe monads in a less powerful language, say Rust? Definitely!

But will you appreciate the power that monads give you in Rust? Probably no.

juxtapose··on Is Haskell a good choice for software security?
> modulo bottom

Since GHC 9.2, with UnliftedDatatypes you can define real uninhabited types!

    {-# LANGUAGE UnliftedDatatypes #-}
    import GHC.Exts
    data Void :: TYPE UnliftedRep where
      Void :: { absurd :: forall a. a } -> Void
juxtapose··on The Invention of Chinese
> the idea that different languages are dialects of Mandarin

I believe most Chinese do think Mandarin and Cantonese are parallel and won't consider Cantonese a dialect of Mandarin. It's better to put it this way: both Mandarin and Cantonese (and many others) are "dialects" of a fictional, idealized language "Chinese". Hence, "dialect" here might be an incorrect translation of "fangyan", which literally just means "regional language".

juxtapose··on The future of Python build systems and Gentoo
Well, if they ask for trouble, trouble will come. Haskell packaging is no different from Rust packaging: native executables statically linked with many small packages; both rely critically on cross-module inline for performance; no stable ABI.

Arch Linux wants to provide an _up-to-date_ compatible set of Haskell packages, instead of relying on the established Stackage like what NixOS does. This certainly causes frustrations as they must do a lot of patches.

End users don't benefit from this decision; they complain about a large number of tiny packages. Haskell devs don't benefit either, as they don't use packages provided by the OS -- just like any other Python/Node/Java/etc dev. Rust programmers use rustup+cargo, Python programmers use pip; likewise Haskell programmers use ghcup+cabal.

That being said, I respect their efforts and the packagers (Felix Yan, et al.). They made great efforts in updating a large number of old packages to be compatible with GHC 9.x.

juxtapose··on Sayonara, C++, and Hello to Rust
> I think Haskell, like Java, and unlike C or C++, promises you still get a meaningful program if you have a data race

This is true (when you insist on mutable shared memory), but in Haskell the safety guarantee is in fact not so far from Rust. The Haskell community is well aware of concurrency issues very early, and they developed a dozen of composable abstractions to solve these problems. (IMHO Rust is the only one that has a truly novel solution in recent years.)

In Haskell, either you have to use `unsafe` functions to share bulk of memory or you don't share memory at all (as mutability is a pita in Haskell). On top of these unsafe functions, you can build other safe abstractions, just like Rust. These abstractions are often available as higher-order functions in libraries, making them highly composable and reusable.

E.g., the canonical memory-sharing data type is `TVar`, which must be access from the `STM` monad [1], guaranteeing both atomicity and data race freedom. (BTW, STM stands for software transactional memory if you aren't familiar with it.) A major offender is `IORef`, and fortunately Haskell provides atomic operations on `IORef`s.

GHC Haskell also offers free parallelism for all pure computations via the `Eval` monad [2].

> Mistakenly instead of processing 1GB per thread, you process the same 1GB on all sixteen threads

This is highly unlikely in Haskell. Haskell emphasizes on composable combinators, so a program that does not share memory would probably look like

    foldr accumulateFunc initValue . mapConcurrently processBatch . split batchSize $ data
(mapConcurrently here is a real function [3].) I'm sure C++, Java, and Rust have similar abstractions, but imperative languages make it too easy for programmers to do `for` loops, making it much more error-prone.

Several array libraries provide safe parallelism. The interface is similar to Rust rayon, but the way they work differs greatly. For example, in Repa [4] you can do

    computeP $ traverse inputArray newShapeFn (\getElem curIdx -> ...)
    
Here `traverse` results in a "delayed" array: the results are not immediately available, and what you are doing is just composing array operations. `computeP` forces the computation to happen _in parallel_. Since GHC is very capable of optimizing intermediate data structures away, this code can compile to very efficient machine code -- there is no mutability at all, yet you get very safe and efficient parallelism.

PS: what Haskell is really bad at so far is safe in-place updates for arbitrary data types (like custom ADTs), which is solved by Rust cleanly. GHC 9.0 added Linear Types [5] to address this problem. Haskell and Rust are both bad at safe in-place updates of arrays, vectors, etc., and are likely to be bad for a long time -- their indices are arbitrary integers, which cannot be analyzed statically at compile time. Haskell probably can solve this problem completely when it gets dependent types [6], whereas Rust is unlikely to support DT any time soon, if ever [7].

[1] https://hackage.haskell.org/package/stm-2.5.0.1/docs/Control...

[2] https://hackage.haskell.org/package/parallel-3.2.2.0/docs/Co...

[3] https://hackage.haskell.org/package/async-2.2.4/docs/Control...

[4] https://hackage.haskell.org/package/repa

[5] https://github.com/ghc-proposals/ghc-proposals/blob/master/p...

[6] https://github.com/ghc-proposals/ghc-proposals/blob/master/p...

[7] https://github.com/rust-lang/rfcs/issues/1930

juxtapose··on Is it stealing to read by the light of your neighbour’s lamp?
Funny that there is an old Chinese idiom 凿壁偷光 (záo bì tōu guāng) referring to this exact act. The idiom literally means "to pierce the wall to steal a light" and the original story goes exactly like how a man wanted to read books but was too poor to afford lights, and he just pierced the wall to steal lights from his neighbor.

So yeah, to Chinese, it is stealing. But the funny thing is that Chinese also think the man in the story is keen on studying, and this idiom is actually used as a praise to people who never stop studying even during the hardships.

juxtapose··on PHP is worth learning and using
Hmmm... Most points in this article are shouting "yeah we have those too!!" but it didn't give any convincing arguments why I (or anybody who doesn't already know PHP) would like to learn and use PHP over other decent modern languages and ecosystems, which happen to have those points as well.
juxtapose··on Dragging Haskell Kicking and Screaming into the Century of the Fruitbat
Haskell is standardized so it's impossible, while GHC can absolutely have editions. I think the infrastructure is already there, with the language extension mechanism and Cabal's default-language setting (e.g. Haskell2010, GHC2021 [1], etc.).

[1] https://github.com/ghc-proposals/ghc-proposals/blob/master/p...

juxtapose··on Rust data structures with circular references
> This is not the same thing, but you seem to think it is.

They are only different superficially.

The deeper problem here is they both assume that "a new, valid value can only reference old, existing values". (For the sake of simplicity, let's pretend Haskell does not have laziness for a moment.) This is reasonable in almost any language because it enables easy inductive reasoning. Rust forbids circular references exactly for this reason, the whole borrow check builds on this principle: a new pointer becomes invalid when the old pointer becomes invalid. You cannot create them in Haskell either due to this very reason, if there is no laziness.

Techniques in Haskell, like tying the knot, work just because laziness makes it possible to reference values in the future. Unfortunately, it also creates possibilities for bottoms, which renders it unusable for a sound proof system -- Rust cannot do the same thing because borrow check should be sound and terminating.

It's easy in C++ because C++ does not guarantee validity of objects. You know, NULL is _always_ an invalid pointer. Rust and Haskell both guarantee that a constructed object is always valid. (ofc, only in most cases where the escape hatches are not used.)

juxtapose··on Why is Tcl syntax so weird (2013)
Tcl is a better shell scripting language. Tcl's escaping is simple and consistent, while bash is almost impossible to grok -- just too many implicit rules to fit in my head.
juxtapose··on An Epic future for SPJ
I used to bash Haskell exceptions but my views changed recently after programming in Haskell for a while.

> all of these can fail, and there's nothing in the type system to alert you of this (in the standard library), such failures just mindlessly throw exceptions like some Java monstrosity

There's `MonadThrow` in Control.Monad.Catch which hints that the monad in question can throw exceptions. Admittedly, partial functions like `undefined` and `error` are still usable...

> Not to mention async exceptions in Haskell, which can happen anywhere, [...] anywhere could be interrupted by an async exception

... and they can throw exceptions everywhere, just like asynchronous exceptions, but it's actually a strength! Haskell enforces a clean separation between impure code (typically in a monad) and pure code. You can only catch exceptions in the IO monad, which often lies outside of the core logic. Due to this unique strength, Haskell is one of the very few languages that can safely terminate running threads.

Impure code can become harder to write because of exceptions, but since you don't write everything in the IO monad, the problem is largely mitigated. Yes, exceptions are hard to get right, and that's exactly why other languages are trying to get rid of, but Haskell makes it quite tractable, (though still quite annoying). Rust used more Maybes and Eithers in the IO monad (to borrow jargons from Haskell), but it's also got panic, which is the actual Haskell exception counterpart.

> and the fact that every value is really of type value|undefined, due to laziness

To be pedantic, Haskell has levity polymorphism, which gives you unlifted datatypes, like in OCaml and Idris. Even older Haskell has unboxed datatypes that are not lifted.

> ...Haskell's love for untyped exceptions everywhere...

Nope, Haskell's exceptions are typed.

juxtapose··on Ask HN: What small tools/utils I can build with Haskell?
Seriously, anything. I use Haskell for any scripts, e.g. crawling web sites. (Python's position has been taken by Haskell in my toolbox.)

Surprisingly, a task as simple as web crawler can be related to so many concepts: regex, parsec, optics, conduit, concurrency, I/O...

The fun of programming Haskell is often you introduce a higher-level concept to your program to make it faster or more generalized, but the code gets shorter and more functional! Wish you a happy Haskell journey and find Haskell fun as much as I do. :-)

juxtapose··on Distributed Systems in Haskell
It's a shame that the Cloud Haskell ecosystem is kind of ... on halt? I wish they at least would review patches and make Cloud Haskell packages compile against latest GHC releases. :/
juxtapose··on Wingman for Haskell: Focus on the important stuff; delegate the rest
Totally love this! Just tried it and it worked quite well.

Things like this could be a reason why we should write in the functional style: completing a typed hole doesn't need you to reason about other implicit states.

juxtapose··on Emacs is special regarding UIs
Yes, Emacs supports a limited form of "rich text". See text-mode.

It's supported by text properties [1] and overlays [2]. Character properties are special attributes attached to a single character, while overlays can attach attributes to a "region" and override old text properties (like div in HTML).

In Emacs,

> A button is essentially a set of text or overlay properties, attached to a stretch of text in a buffer. [3]

The Emacs display engine is sorta like an HTML render engine.

[1] https://www.gnu.org/software/emacs/manual/html_node/elisp/Te...

[2] https://www.gnu.org/software/emacs/manual/html_node/elisp/Ov...

[3] https://www.gnu.org/software/emacs/manual/html_node/elisp/Bu...

← PreviousPage 2 of 2