Hacker News new | past | comments | ask | show | jobs | submit login

this is great, thank you.

In the languages I use more frequently, one reason partial application needs to be done more explicitly is because not all arguments are necessarily required. Frequently these languages support either maps or "keyword arguments" to solve the problem of allowing some arguments to be optionally specified with defaults.

Is it common in this alternative style of language to have named arguments, such that you could still apply "optional" arguments in a non-positionally defined order by name? I'd love to be pointed to some information on how this "school" of languages handles problems where this is a less well-defined order of partial application.




So Passerine has a record type, and is row-polymorphic. Names keyword arguments in passerine would look like:

    draw_arc {
        x:      3,
        y:      5,
        radius: 10,
        start:  0,
        end:    2 * 3.142,
    }
As for defaults, this is something a bit more difficult. In a dynamic language, you can just try getting keys and replacing missing ones with the default ones.

However, in a static language, this isn't quite possible. a missing field on a record is a compile-time error, not a runtime one. Even row-polymorphic type systems, which are generally more lenient with respect to records aren't a solution.

Rust has `Default::default()` which allows one to splice in default values when a struct is constructed. This relies on the `..` splicing syntax; I've been considering something similar for Passerine, but I haven't come to any conclusions yet. I like this because it makes the fact that you're using defaults explicit, but at the same time I'm against it because it feels like unneeded boilerplate:

    draw_arc {
        x: 3,
        y: 5,
        ...Arc::default(),
    }
Another option is to just defer field checking to runtime, and allow these errors to be handled. Given that I want to be able to compile Passerine to machine code at some point, I'm not sure whether this is a good idea:

    -- if the expression errs, replace it with default
    syntax expr 'default def {
        match (try expr) {
            Ok v -> v,
            Err _ -> def,
        }
    }

    draw_arc {
        x: 3,
        y: 5,
    }

    draw_arc = arc -> {
        full_arc = { 
            x: (arc.x) default 0,
            y: ... 
        }
    }
But I'm not sure which avenue I should take at this point in time.

> I'd love to be pointed to some information on how this "school" of languages handles problems where this is a less well-defined order of partial application.

I know Ocaml has labels, which are basically public function names. so like:

    let f ~banana = a + 1;
means that the type signature is something like:

    val f : banana:int -> int = <fun>
Notice how `banana` is a part of the type signature. There are also optional named parameters:

    let f ?(banana = "ripe") = ...;
Which when used have to be explicitly listed:

    f ~banana:"rotten" ();
That's about it. What are your thoughts?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: