HN user

kripke

60 karma
Posts0
Comments23
View on HN
No posts found.

Sort of, I think?

`type 'a t = Cons of 'a * 'a t | Tail` is defining a type with a constructor `Cons` with two arguments and a constructor `Tail` with zero argument. You write values of type `'a t` as `Cons (a, b)` and `Tail`.

`type 'a u = (::) of 'a * 'a u | []` is defining a type with a constructor `(::)` with two arguments and a constructor `[]` with zero argument. You build values of type `'a u` as `(::) (a, b)` and `[]`.

The rest comes from the special syntax support in OCaml for the `(::)` and `[]` names. Namely, `a :: b` is parsed as `(::) (a, b)`, and `[a; b; ...; z]` is parsed as `a :: b :: ... :: z :: []`, and hence as `(::) (a, (::) (b, (::) (..., (::) (z, []))))`.

There is a balance to find between not enough annotations and too much annotations that one has to find. My algorithm is to write few annotations by default, and my answer to error messages I do not understand is to add "obvious" annotations (e.g. type of arguments) to tell type inference what I expect. Rarely does that solve the underlying issue, but it often makes the error message much clearer.

With experience, I am more or less able to preemptively add the annotations that will probably help (e.g. aiming avoid accidentally polymorphic functions, the return type of mutually recursive functions, etc.).

I don't think I have ever gotten "This expression is of type X but an expression was expected of type X" outside of the toplevel with type re-definitions, and recent OCaml versions have a nice error message for this now:

    Error: This expression has type t/1 but an expression was expected of type
             t/2
           Hint: The type t has been defined multiple times in this toplevel
             session. Some toplevel values still refer to old versions of this
             type. Did you try to redefine them?
In general the error messages have been continuously improving in recent years.

I almost never click on a radio/checkbox input because clicking on the label is just so much easier, and I loathe when a fast-and-loose web developer neglects to properly set up labels for their checkboxes. That said, outside of tech circles, few people are aware that you can usually click on the text associated with a checkbox instead of the checkbox itself, so I'm not sure it would help much for a target demographics of "users over 60".

Unless of course you were suggesting to use labels to implement bigger visual checkboxes, which I gather is what the GP is already referring to with "Currently the only reliable way is to hide these inputs and replace them with images."

Even if the right to be forgotten is a moral good, it is not (and should not be) an absolute right trumping other rights such as freedom of expression (also a moral good). Twitter can decide to stop hosting the content you published on there, either at your request or at their discretion (e.g. banning your account), but forcefully removing content from another operator's website is overreaching, it is simply not their call to make.

Technicolor Tokyo 4 years ago

They are indeed edited, it is mentioned in the article: “My approach to photography is similar to filmmaking, in how they take a shot and build off it with color grades and adding effects. It’s less photography in the traditional sense and more of a hybrid. I’m not a photojournalist.”

That is not a good argument. What matters to companies is: "is this stable enough not to be a concern", and according to GP Nix falls short on that front currently. They will not care how you achieve this --- C, a rigorous process and a world-class army of developers like the kernel is fine; Rust, a sloppier process, and less developers will be fine too. Heck, I'm not sure they'd care if you deliver stable and robust software using hand-written assembly, if not out of concerns for long-term support (and your mental health).

The background on our side is that we did do quite a lot of profiling and investigation of the current evaluator - last year, informally, over video chats and IRC. We have a bunch of logs and various perf measurements spread out over some machines but right now the knowledge lives in our heads, mostly because at the time we did not expect this to spawn a serious project.

It's good to hear that you did do some profiling, even if the results are not public! Of course I would not expect the details in the initial announcement, but I would have expected a mention of this work. At least I have a much higher confidence in the success of this project now than just after reading the announcement.

Switching between the proper implementation of high-level concepts is a staple of untyped (and sometimes typed) runtimes, so in this context the changeset makes more sense than simply "replacing an array-backed implementation with an std::vector-backed implementation" as described, thanks for the explanation!

I'm also not putting any blame on Nix --- the fact that the performance of the evaluator is such an issue is in a way a testament to its success. Unfortunately large, long-lived systems do require active care to enforce proper boundaries between subsystems, and it's a shame if it has got to a point where it's no longer possible to reinstate that separation.

I don't know much about Nix, although it has been on my radar for some time. The claim that the language performance is bad pops up time and again, and I'm sure many people would be happy to have a faster alternative --- so props to them for trying to address this clearly important problem.

That being said, in perusing related issues on GitHub such as [1], I have found no serious attempts to even profile the damn thing. The typical attempt seems to be throwing a random idea at the evaluator and crossing fingers. The example of a "performance experiment" [2] from the article is self-described as follows:

Add an alternative impl of the now-abstract Bindings base class that is backed by a std::vector, somewhat similar but stylistically a little superior to the array-backed implementation in upstream nix.

I fail to see how that is a performance experiment when it does not mention performance at all.

The post also mentions issues with the general Nix design and a desire to modernize it, which I am unqualified to comment on, but seems a worthwhile endeavor in and of itself. I do hope that they won't end up writing a new evaluator for the Nix language without a proper understanding of what makes the current one slow and a clear plan not to repeat its mistakes, or the new one risks being just as slow as the old one.

[1] https://github.com/NixOS/nix/issues/2652

[2] https://cl.tvl.fyi/c/depot/+/1123/

I just skimmed through the code, but as far as I can tell, the main point is that this code is multi-threaded.

Which, sure, gets the job done faster than the single-thread `odiff` on a single image, but is quite irrelevant for a tool marketed for tests/CI where many images are likely to be compared in parallel already (and maybe a single core is even available).

You can still do this in C, with the same implementation Lisp uses under the hood. C being C, there is a bit of syntax boilerplate. I also omitted some details which may have been relevant at the time such as ensuring no cast from function pointers to data pointers (not hard to handle, but makes the code a bit longer).

    #include<stdio.h>
    #define DX 0.0001
    typedef double (*function)(double);
    typedef double (*closure_body)(void*, double);
    struct deriv_env { function f; };
    struct closure { void* env; closure_body body; };
    #define CALL(c, x) ((c)->body((c)->env, (x)))
    double deriv_body(void *env, double x) {
        function f = (deriv_env *)env->f;
        return (f(x + DX) - f(x)) / DX;
    }
    void deriv(function f, struct closure *out) {
        out->env = (void *)f;
        out->body = deriv_body;
    }
    double cube(double x) { return x * x * x; }

    int main(void) {
        struct closure cube_deriv;
        deriv(&cube, &cube_deriv);

        printf("%f\n", CALL(&cube_deriv, 2.));
        printf("%f\n", CALL(&cube_deriv, 3.));
        printf("%f\n", CALL(&cube_deriv, 4.));

        return 0;
    }

Connecting to server:4242 as "user":"hunter2"

as an example of DEBUG logging is very wrong. Passwords should not end up in your logs, ever.

Not GP, but you are probably looking for the "Neural Architecture Search" series [1] [2] [3]. First one uses something like 1k GPUs for a month, next one is a bit more reasonable, and the last one actually has a reasonable training time, and has comparable performance to DARTS (see ENAS in comparison tables).

1: https://arxiv.org/abs/1611.01578 2: https://arxiv.org/abs/1707.07012 3: https://arxiv.org/abs/1802.03268

How I review code 8 years ago

1000 should really be handled by automated tools. Takes useless burden from the reviewer, and emotionally easier for both sides too.

This is interesting, and thanks for trying to clean up the protocol, but isn't this an orthogonal issue? The problems you are describing seem to be related to using an undocumented protocol, which is unrelated to using a custom serialization format vs building upon an existing one.

Building upon an existing, well-documented, and relatively sane serialization format (protobuf, capn't proto, message pack, json, heck even bencode for all I care) is usually a good thing, and so is decoupling the messages from the details of an implementation's internals. Language and framework internal serializers (such as Python's pickle or, apparently, Qt's serializer) tend to make it harder to achieve both goals.

FYI, the time alloted to each challenge seem to increase with the difficulty (the first couple of problems are 48 hours, then 72, then 96, etc.).

It is also on the blackboard at the end (around 0:57), and possibly on some other places. Google "sponsoring" them in exchange of putting an IP address in their trailer is something I would absolutely see them do.