HNHacker News
TopNewBestAskShowJobs

sullyj3

1,004 karma · joined July 4, 2014

submissionscomments
sullyj3··on Upcoming/proposed breaking changes to Haskell
It could be interesting to have an `Unsafe` convenience module that is imported by default in the repl, but not in source files. Maybe that would be too confusing for beginners though.
sullyj3··on Upcoming/proposed breaking changes to Haskell
Yep, type checking clearly can't be decidable, since the type system is turing complete.

Imo inference is a bit overrated anyway. I find annotations to be very useful.

There's a series of steps here:

- "Static type annotations are too verbose, dynamic languages allow you to avoid the ceremony." - "But Hindler Milner type systems can infer the types, so you usually don't have to write the type annotations!" - "Writing type annotations is useful anyway, because it serves as valuable documentation, makes reasoning about the program easier, and results in more useful type errors."

Thinking about it more now, there's another step: - "If you have good type inference, you can use editor tooling (eg the LSP) to automatically insert the type signatures for you!"

sullyj3··on Show HN: Luna is a Clojure domain specific language that translates to regex
The fact that nobody wants to learn or use regex is a pretty strong indicator that it's not a very good language. I think we've largely settled on it as matter of historical contingency rather than because it has any particular merit. For starters there's no capacity to name expressions in order to combine them at a higher level of abstraction.

I'd love to see something like Rosie take off as an alternative: https://rosie-lang.org/about/

sullyj3··on The Bongcloud Attack
> by Bongcloudmaster (BM) Andrew Fabbro

Brilliant

sullyj3··on Why Co–Star Uses Haskell
It's not supposed to be good procedural code, it's supposed to be illustrative of the fact that a lot of code which people are used to seeing in procedural languages, which only involves assigning to a variable once, can be translated into a pure haskell function very straightforwardly, and it doesn't look intimidatingly esoteric like many people seem to expect. I can just as easily do it with strings if you're concerned about it being mathematical.

I agree that there are many problems more naturally represented by procedural code, and as such it's important for every language, even functional languages, to have good constructs for representing a series of steps.

Luckily, Haskell has such a construct in do notation. It looks like this:

    main = do
      putStrLn "What's your name"
      name <- getLine
      putStrLn ("Hello, " ++ name)
I'm not familiar with MongoDB, but I found a haskell library for that and the example looks relatively straightforward to me, modulo possibly some unfamiliar syntax. It's a bit long, but it's doing more than just an insert. [1]

I've heard the cake argument many times, and I agree that it's more naturally modelled as a series of steps. But I find it frustrating, because I've never heard a convincing argument for why the fact that one particular problem is more intuitively modelled as a sequence of steps, means all problems are.

For example, imagine if you were never allowed to declaratively specify a DOM again using HTML, but instead you had to construct it as a series of calls to element.appendChild(). Would that really make your life easier? There are many problems for which a declarative description, not a procedure, is much more straightforward to understand.

Another point is that you can also think of applying functions in succession ("function composition") as a series of steps! I find this pretty intuitive.

For example, here's a function which takes a list of words and shouts them. The steps are: First concatenate the words together, then capitalize the resulting string, then append an exclamation mark:

    λ » shoutWords = unwords .> capitalize .> exclaim
    λ » shoutWords ["i'm", "shouting"]
    "I'M SHOUTING!"
I think you're right about needing to have a certain level of smarts to get Haskell, but I think this is a consequence of some more advanced Haskell features (Typeclasses + higher kinded polymorphism), rather than the functional paradigm itself. For example, I think Elm is probably very approachable for people with a wide variety of different levels of mathematical ability.

I think it's very easy to assume that functional programming is inherently more difficult, when it might well be that all that's going on is that people are more used to procedural programming because that's what they were taught first. I really would encourage anyone who thinks FP is inherently difficult to have a crack at learning Elm.

[1] https://hackage.haskell.org/package/mongoDB-2.7.1.1/docs/Dat...

sullyj3··on Why Co–Star Uses Haskell
From that same paragraph:

> That said, there are ways of dealing with this in languages like Python, they're just a little more verbose and you don't get the compiler checking that you've exhaustively handled all cases, for example. It won’t compile, it won’t accept that idea.

sullyj3··on Why Co–Star Uses Haskell
A cynicism filter?
sullyj3··on Why Co–Star Uses Haskell
> Using long sequences of poorly-labeled, nested arrow function returns is great fun until you have the task of deciphering someone else's.

Something like that would be considered bad Haskell code, yes. Haskell is designed from the ground up to support the functional paradigm. When people try to use functional style in languages that were designed with primarily procedural style in mind, the result is often ugly and difficult to follow. You just don't have the same issue in a language that's designed from the beginning as a functional language.

Something that people tend to miss is that you can write code that very much looks like a lot of procedural code in haskell:

    let 
      x = 1
      y = x + 5
      z = 10 + y + z
    in x + y + z
You can have bindings, just like you might use variables in a (eg) python function. The only difference is that the bindings are immutable. That turns out to not be as restrictive as you might expect - a lot of good python code only assigns to a given variable once.

I think it's a fair criticism to say that Haskell code can become opaque when it relies on more advanced language features and esoteric GHC extensions. The solution to this is to be disciplined and selective as a team about choosing which features you believe are worth their complexity/onboarding cost, and sticking to those choices.

Conversely, I find Haskell code that doesn't use those extra features to be much easier to understand than equivalent code in other languages, due to the extra guarantees I have about the code. For instance, I know that variables won't be mutated out from under me, things can't be null where they shouldn't be, and there are plenty of other assorted guarantees that come from having access to an expressive type system.

sullyj3··on Why Co–Star Uses Haskell
Mostly because it takes a lot of patience and dedication to get to a productive level. It's a bit like vim - steep learning curve, but fantastic to use once you know what you're doing.
sullyj3··on Why Co–Star Uses Haskell
Yes, a significant chunk of Haskell code usually does end up living in whatever monad (the context that represents IO computations) the app is using.

This doesn't negate the advantages of tracking effectful code in the type system, and there's still plenty of code that can be pure.

sullyj3··on Do-nothing scripting: the key to gradual automation (2019)
Seems like premature abstraction to me. It's not difficult to make that change if you need it. In any case, I'm really struggling to envisage a scenario where you would need them to be classes - why couldn't a more automatic version still be a function?

In my opinion, in order to justify instantiating an object, it should actually contain data, and that data should actually be accessed by code other than methods internal to that class. This rules out using an object to represent a procedure - regular functions subsume that functionality.

Before first class functions became commonplace, it did make sense to use objects as procedures in some OO languages, to allow you to pass them around as values. Since most languages these days do have first class functions, this has become less necessary.

If you want a class in order to to split the procedure into multiple methods with access to shared mutable state, that's totally fine - you can just use nested functions to do the same thing.

sullyj3··on Do-nothing scripting: the key to gradual automation (2019)
Side note: - I don't understand why classes are needed here. instead of

    procedure = [
        CreateSSHKeypairStep(),
        GitCommitStep(),
        WaitForBuildStep(),
        RetrieveUserEmailStep(),
        SendPrivateKeyStep(),
    ]
    for step in procedure:
        step.run(context)
Why not make them functions instead of classes. The URLs can be locals instead of class variables and the context argument becomes an argument to the function rather than a run method.

    procedure = [
        createSSHKeypairStep,
        gitCommitStep,
        waitForBuildStep,
        retrieveUserEmailStep,
        sendPrivateKeyStep,
    ]
    for step in procedure:
        step(context)
The OO is just gratuitous. Personally I probably wouldn't even bother with the for loop/context and would just pass the data that's actually needed by each function into it manually.

    createSSHKeypairStep(username)
    gitCommitStep(username)
    waitForBuildStep()
    email = retrieveUserEmailStep(username)
    sendPrivateKeyStep(email)
I get that it feels more modular - "oh all I need to do to add a step is add it to the list!" But like, all you need to do to add a step is add a line of code. There's no difference.

Much easier to see how the data is actually flowing that way. I found the fact that the context was mutated in a function it was passed into kind of gross. It's just globals with extra steps. Besides, this is less LOC anyway.

sullyj3··on Get started making music
But... why? Why is important that people use the technically correct name rather than the more convenient one that's in common use already?
sullyj3··on XMonad – The Automated Tiling WM
I don't know about other wms, but in i3, floating a window is just a matter of pressing super+space. Moving it around and resizing is very ergonomic as well, it's just super+left click drag and right click drag respectively. The really nice thing about the resizing is that you don't have to hit a tiny window border target with your mouse, super+right click just snaps to the nearest border of the window you're in.

My guess is that most other tiling wms would have a straightforward way to float windows as well.

sullyj3··on We moved from Pony to Rust
Rust is a language nobody uses?
sullyj3··on Don't write bugs
We should offload this responsibility to our tools as much as we possibly can.

https://blog.codinghorror.com/falling-into-the-pit-of-succes...

sullyj3··on Structural pattern matching in Python 3.10
I think they're right that it would be too foreign to python to be a good addition, but this really just goes to show that expression oriented languages, as opposed to statement oriented ones, are the way to go.
sullyj3··on Python Anti-Pattern
Having a bug caused by mutable state occur inside a "lambda function" really throws into relief what a misnomer that is.
sullyj3··on Functional programming is not popular because it is weird (2016)
Having written Haskell for a few years, the concepts are kind of interchangeable in my mind. I think of recursion as being basically a loop, and a loop as basically the same thing as recursion. To the point where it seems natural to me to name a recursive helper function `loop`. Obviously they're not exactly the same, but with familiarity they can be translated trivially.

I think it's really just a matter of prolonged exposure to make recursion seem intuitive.

sullyj3··on Functional programming is not popular because it is weird (2016)
It depends on the domain. In performance critical code, I agree that it usually makes sense to use an imperative language. However, not all code is performance critical. Also note none of this is to say that fp is inherently incapable of high performance code - properly tuned Haskell can be competitive with C. Libraries like Streamly[1] are designed with extremely high performance in mind. But I agree reasoning about performance is much more difficult and requires more expertise.

[1] https://hackage.haskell.org/package/streamly

sullyj3··on Functional programming is not popular because it is weird (2016)
There are tradeoffs to writing functional code in langauges designed primarily for imperatively. Another comment mentioned efficiency.

Another is that in a pure language, you can look at a function and know for a fact that nothing you're seeing can ever be mutated. This eliminates a massive source of cognitive load when trying to read and understand code, as well as eliminating all sorts of bugs related to the program being in the wrong state. If you're trying to write functional code in a language not designed for it, you're missing out on those benefits.

Now, it's absolutely the case that the tradeoff may be worth making depending on the person and circumstance. But it does exist.

sullyj3··on Functional programming is not popular because it is weird (2016)
This is why every time this stuff comes up I plug the haskell flow package. Imo, it should be in the prelude.

https://hackage.haskell.org/package/flow-1.0.22/docs/Flow.ht...

sullyj3··on Nvui: A NeoVim GUI written in C++ and Qt
Just above the gif:

> Customizable cursor height (see :h NvuiCaretExtendTop and :h NvuiCaretExtendBottom)

  Ex. :NvuiCaretExtendTop 200, :NvuiCaretExtendBottom 100 (see below)
sullyj3··on Emacs Modernization: Simple Changes Emacs Should Adopt (2006)
Title could probably use a (2006)
sullyj3··on All you need is call/cc (2013)
Uh.. what? There isn't even a concept of mutation in lambda calculus.
sullyj3··on The problem of effects in Rust (2020)
I find in practice that even though I don't have to write the transformers myself, `lift`ing and `unlift`ing things is a pain in the ass. Once you try a proper algebraic effect system, it's hard to feel like transformers are an adequate solution.
sullyj3··on Weird Languages
It has compile time programming designed to subsume those features. So eg a generic struct becomes instead a compile time function that takes a type and returns a struct
sullyj3··on The problem of effects in Rust (2020)
I mean, monads famously don't compose - you have to write a bunch of monad transformers.
sullyj3··on The problem of effects in Rust (2020)
Unison has an algebraic effect system, under the name "abilities"

https://www.unisonweb.org/docs/abilities/

sullyj3··on Nimforum: Lightweight alternative to Discourse written in Nim
> 1- There is excessive white-space everywhere (like every other modern web-app). I feel like it was designed as a mobile-first solution.

So many programmers have this obsession with interfaces having every available piece of information displayed all at once. I just don't understand the appeal. I find these sorts of interfaces confusing and overwhelming, I literally can't think straight when I look at them. I immediately forget what I was doing due to all the distractions.

← PreviousPage 3 of 18Next →