Stream: ideas

Topic: importing type variable names


view this post on Zulip Folkert de Vries (Mar 11 2022 at 18:34):

Say we have Result.withDefault : Result ok err, ok -> ok and we use this in a module

foo = Result.withDefault

What should the type of foo be. Today it is actually

foo : Result ok *, ok -> ok

But the natural result of some changes I'm making turns that into

foo : Result ok err, ok -> ok

And I actually like that better I think

So, should we import type variable names?

view this post on Zulip Folkert de Vries (Mar 11 2022 at 18:40):

we'd need to actively do work to get rid of those names btw

view this post on Zulip Richard Feldman (Mar 11 2022 at 18:56):

the times when this would come up would be in the repl, in the editor when asking the name of the type, or in an error message, yeah?

view this post on Zulip Folkert de Vries (Mar 11 2022 at 19:00):

exactly

view this post on Zulip Folkert de Vries (Mar 11 2022 at 19:00):

right now in the repl this would show the err because technically that function is not imported

view this post on Zulip Folkert de Vries (Mar 11 2022 at 19:01):

but in the general case the name would be dropped today

view this post on Zulip Folkert de Vries (Mar 11 2022 at 19:01):

however, with some changes https://github.com/rtfeldman/roc/pull/2703/files that will make moving types between modules much faster,

view this post on Zulip Folkert de Vries (Mar 11 2022 at 19:01):

this changes

view this post on Zulip Folkert de Vries (Mar 11 2022 at 19:02):

I think because we send a rigid over now, instead of a flex

view this post on Zulip Folkert de Vries (Mar 11 2022 at 19:02):

and rigids must have a name

view this post on Zulip Folkert de Vries (Mar 11 2022 at 19:02):

and you can't just pick * because the rigid might occur elsewhere in the signature

view this post on Zulip Ayaz Hafiz (Mar 11 2022 at 19:21):

I agree I think we should send the name over especially if it comes naturally with the current impl

view this post on Zulip Ayaz Hafiz (Mar 11 2022 at 19:22):

Semantically it is no different, but saying err instead of * seems a lot more expressive

view this post on Zulip jan kili (Mar 12 2022 at 10:43):

This is a little off topic, but I expected the first code example to crash the REPL because I'm used to Roc expecting my functions to be applied.
I expected this:

foo = Result.withDefault

to have to be rewritten as this:

foo = \x, y -> Result.withDefault x y

However, the first code example works fine! I was pleasantly surprised that g = f and g f both work as expected:

» f = \x -> x * 2
… g = f
… g

<function> : Num a -> Num a

» f = \x -> x * 2
… g = \x -> x 3
… g f

6 : Num *

» f = \x -> x * 2
… 3 |> f

6 : Num *

»

Is this new behavior? Have I been too cautious with my function references? I've felt the need to do a lot of anonymous \x -> f x functions, especially in pipelines... but I'd love to not have to!

view this post on Zulip Brian Carroll (Mar 12 2022 at 11:16):

I don't think there's anything new about this behaviour. In your example, you mention something about functions having to be applied, but the foo function is not applied so it's no different from the Result.withDefault inside it.
But something comes to mind that might be relevant. If you want to partially apply a function (i.e. give it one argument now and another later) then you do need to wrap it in another function.

y = 123
foo = \x -> Result.withDefault x y
foo (Ok 5)

But if you're providing all arguments at once, there's no need to do that.
In closely-related languages like Haskell/Elm/Ocaml/F#, you wouldn't need the wrapping function because they have automatic currying. But Roc doesn't have that.

view this post on Zulip jan kili (Mar 12 2022 at 11:18):

Yeah, that makes sense, since Roc doesn't have partial application or currying. However, I thought that extended to non-application (or whatever the phrase would be for partial application with zero parameters applied).

view this post on Zulip jan kili (Mar 12 2022 at 11:21):

On second thought, I've used a lot of non-applied functions in pipelines... but sometimes I'd need to wrap them in a lambda for whatever reason... maybe those were just more-complex functions. Okay!

view this post on Zulip Brian Carroll (Mar 12 2022 at 11:24):

Ah OK that must be it then. The idea that functions can be used as values is pretty core in functional languages, so it would be a bug if it didn't work somewhere.

view this post on Zulip jan kili (Mar 12 2022 at 11:26):

Hmm, wow I swear this didn't use to work... I have a bad memory, though.

» f = \x -> x * 2
… g = \x -> x * 3
… h = \x, y -> x 4 + y 5
… h f g

23 : Num *

»

view this post on Zulip jan kili (Mar 12 2022 at 11:28):

Maybe it wasn't working (at some point in the past) due to some bug, but then I just assumed it wasn't supposed to work.

view this post on Zulip jan kili (Mar 12 2022 at 11:28):

Hooray! This is super clean and practical :smiley:


Last updated: Jun 16 2026 at 16:19 UTC