HNHacker News
TopNewBestAskShowJobs

kbp

807 karma · joined October 19, 2016

submissionscomments
kbp··on Amber: Programming language compiled to Bash
Er, actually

  x = 2
  x = "foo"
  [y] = [3]
  [y] = ["bar"]
Sorry, I didn't re-read the code before translating.
kbp··on Amber: Programming language compiled to Bash
I'm not sure what you find incomprehensible about the first example. The syntax is pretty standard. The only exotic thing is `$`, which is basically just like putting brackets around the rest of the line. Here's the first example roughly translated to Python:

  def main():
      x = 2
      [x] = ["foo"]
      y = 3
      [y] = ["bar"]
      print(x + y)
Seems about the same level of comprehensibility to me. Is there anything in particular you find difficult to understand?

The second example is expanded out and not how a person would normally write it, but if you're familiar with the basic concepts it's using, it shows why it works very clearly; think of it like assembler.

kbp··on Amber: Programming language compiled to Bash
It works the same way in Haskell, eg

  main = do
    let x = 2
    let x = "foo"
    y <- pure 3
    y <- pure "bar"
    putStrLn $ x ++ y
which is really the same as

  main =
    let x = 2
    in let x = "foo"
       in pure 3 >>= \y ->
                       pure "bar" >>= \y ->
                                        putStrLn $ x ++ y
So it works pretty naturally where each assignment is kind of like a new scope. If the type system is good, I don't think it really causes issues.
kbp··on Why are so many young Americans adopting fake British accents?
Surely not in Canada?
kbp··on Why are so many young Americans adopting fake British accents?
I can hear them and tell that they're different accents, but I don't really distinguish them, I would call them both "British" and I wouldn't know which one's more posh.
kbp··on Pipe Operator (|>) For JavaScript
Usually that effort should go toward naming functions rather than their results, though, and if the functions have good names, the results don't need them. In this example, `other_function` could have been named `get_user_data`, `new_function` could have been called `extract_user_details`, whatever.

Once you have good function names, which you should generally be spending a lot more effort on than good local variable names, you won't find any value in adding variables like `var foo = get_foo()`.

kbp··on Escaping strings in Bash using !:q
Works in Ruby:

  irb(main):001:1/ puts(%r
  irb(main):002:1* a+
  irb(main):003:0> .match? %q aaa )
  true
kbp··on Ask HN: Resources to grok Emacs and use it well?
You can also ssh in via Emacs with Tramp, and use your highly customised Emacs to edit remotely.
kbp··on My C code works with -O3 but not with -O0
Unsigned integers are still specified to wrap.
kbp··on ChrysaLisp
> Clojure has cons, car, cdr which you can use in the classic Lisp sense. The only thing you CAN'T do is have a dotted pair or dotted list in the last cons cell.

So, it doesn't have them in the classic Lisp sense. Conses are just pairs. Using them as such isn't exotic. (cons 1 2) being an error in Clojure isn't a minor thing, it's very unique compared to other Lisps. It has a very different definition of cons.

kbp··on Homoiconicity isn’t the point (2012)
Yeah, it's definitely a taste thing, but as the first style isn't used in Lisp, comparing its readability doesn't really make sense. Indentation is important to reading Lisp. Indenting it in an odd way makes it harder to parse. It's a bit like giving

  def
    foo(x)
    bar(x)
  end
as an example of Ruby syntax being overly homogeneous.
kbp··on Homoiconicity isn’t the point (2012)
That isn't how that defun would normally be formatted, though. Lisp knows that the 'body' part starts with the 3rd argument (the same way Clojure knows it starts with the second), so it indents the lambda list farther right (if it doesn't fit on the first line, otherwise it would go there).

For my eyes, [] aren't distinct enough from () to make the second style preferable. I'd rather have indentation to set it apart.

kbp··on Why Lisp macros are cool, a Perl perspective (2005)
Could you expand on how Forth differs from Lisp? I don't know Forth.
kbp··on An interview with Barbara Liskov
SICP called it design by wishful thinking; I always liked that.
kbp··on Client-side web programming in Haskell: A retrospective
You're mixing your "playing by JS' rules" point with just general Elm features. Faster compilation speed, faster executables, and smaller executables are not JS' rules, they're just generally desirable things to have. "Faster than Webpack" and "no runtime exceptions" are certainly not the JS world's rules (does Purescript have runtime exceptions?). That a typical JS developer can get up to speed quicker in Elm seems very nebulous to me; why? Could you elaborate more on what you're talking about? How is Purescript not playing by JS rules, other than being (I assume) slower than Elm?
kbp··on The beauty of functional languages in deep learning – Clojure and Haskell
> If you have a recursive data structure, using tail recursion over that structure is significantly more straightforward than writing iteratively. I actually wrote a comment about this recently: [0].

> [0] https://news.ycombinator.com/item?id=20896327

That example isn't tail recursive, though. The Python version is more difficult to read because you're using a manual stack instead of relying on the built-in one. An iterative algorithm, whether written using lexical recursion or a for loop, would entirely remove the use of a stack, not just hide the stack in your language implementation. Converting an iterative algorithm between the two forms is a simple syntax transformation, and doesn't introduce bookkeeping like that. Converting a body recursive function to iterate with an in-language stack introduces a lot of noise even if you use tail recursion to do the iteration.

The tail recursive Haskell version of your Python isn't much better:

  sumTree :: BTree -> Int
  sumTree t = sumTree' [t] 0
    where sumTree' [] total =
            total
          sumTree' (Leaf v : rest) total =
            sumTree' rest (v + total)
          sumTree' (Branch v l r : rest) total =
            sumTree' (l : r : rest) (v + total)
kbp··on Rust in Large Organizations
I believe they're still object pointers in CPython, they're just ordinary singletons; in other implementations, they aren't even singletons. Python's object model doesn't have primitives. Adding special rules around them would significantly complicate the language as well as limit the implementors' ability to fiddle with the ranges of pre-allocated instances, for minimal benefit.
kbp··on Rust in Large Organizations
I don't think that's a great example for Python; that's just knowing what "is" is for. The fact that it works the same as == for small integers in CPython is an optimisation showing through, but only in a place where it doesn't really matter.

You still need to have a grasp on the difference between reference equality and value equality without getting into anything anyone would call tricks or implementation details (eg, after `x = []; y = []; x.append(1)`, how many elements does y have?).

kbp··on Python Is Eating the World
Right, they describe different aspects of how types work in a language.
kbp··on Python Is Eating the World
Static typing is not a superset of strong typing, they're on different axes. Strong vs weak typing (which I explained in the second paragraph) is about how strictly types need to match expected types before you get a type error. Static vs dynamic typing is about when you get a type error (during a static typechecking phase, or at runtime when you try to use a value as that type).

When you say the type cannot change, that's ambiguous: do you mean the type of the value a variable holds, or the type of the value itself? In C (a statically typed language), "int x" means that x will always hold an int, but you can still assign a pointer to it, it just turns into an int (weak typing). In Python (a dynamically typed language), the variable "x" wouldn't have a type (so it could hold an int at one point and a string later), but the value it holds does, and because it's strongly typed, it would throw a type error if you attempted to use it in a place where it wanted a different type (eg, `1 + "2"` does not turn 1 into a string or "2" into an int).

kbp··on Ask HN: Why is everyone here so obsessed with Lisp?
When people say that, they mostly just mean that it has lexical closures, I think.
kbp··on Python Is Eating the World
Why aren't statically typed programs really just dynamically typed programs where all the types happen to be statically inferable?
kbp··on Python Is Eating the World
Static typing means that types are figured out statically by looking at the source code, and type errors are detected then when it notices a mismatch. Dynamic typing means that types are worked out at runtime by looking at live objects when code operating on them executes.

Strong typing means that types cannot be substituted for other types. In C, you can write `int x = "one"` and the char * (address of) "one" is automatically converted to an int, or in Javascript you can write 1 + "2" and a string "1" is automatically created; depending who you're talking to, either or both of these qualify as weak typing.

They're both spectrums, and commonly confused with each other.

kbp··on Python Is Eating the World
Not automatically coercing values is all that strong typing means. Getting a type error before you run the program is static typing. They're separate axes, and both useful to talk about in a language.
kbp··on What’s New in ES2019
A method named "method!" means that it's a somehow "unsafe" version of the method "method". A lot of the time it means "destructive version," but if there's no non-destructive version, the destructive one won't have a ! (eg, Array#shift), and sometimes ! means something else (eg, Kernel#exit! is like Kernel#exit, but doesn't run any at_exit code).
kbp··on What’s New in ES2019
Threads are C11, not C99.
kbp··on History and Effective Use of Vim
Use tramp with Emacs and you can interact with remote machines as if they were local. Who cares if the server only has vim, you have Emacs.
kbp··on Programming Patterns I Like
The significant difference is that in Rust, like in Lisp, `if` is an expression, so if-else essentially is the ternary operator.

    const x = cond1 ? a 
            : cond2 ? b
            : c
becomes in Rust

    let x = if cond1 { a }
            else if cond2 { b }
            else { c }
kbp··on Why ['1', '7', '11'].map(parseInt) returns [1, NaN, 3] in JavaScript
The part that is relatively unique to JS is where extra arguments passed to a function are silently ignored. In most every other language, the function passed to map takes 1 argument, which is also the common case in JS. But JS always passes 3 arguments to that function. I don't think it's optional parameters that people find confusing, it's the interplay between optional parameters and functions whose interface depends on functions they accept as arguments ignoring extra arguments.
kbp··on Why I Don't Like Golang (2016)
It doesn't matter when you're making the edit, it matters when you're looking at the diff and skimming through a hundred identical changes for the things that are actually different.
Page 1 of 12Next →