Right now, you can only specify a type when you define the variable
x : U64
x = 2
f : Num -> Str
f = \y -> Num.toStr y
What if you could add type assertions in the middle of an expression? An unreaslistic example to show it:
a : Str = (Str.joinWith (List.map ([1.0, (2.0 : Dec)] : List Dec) \(x : Dec) -> Num.toStr x) : List Str) ","
obviously it wouldn't be used that much in long single line expressions like that, but it'd be more useful in long pipelines to keep track of the type through the pipeline.
x : Str =
[1.0, 2.0]
: List Dec
|> List.map Num.toStr
: List Str
|> Str.joinWith ","
: Str
or a more complicated example where seeing mid-expression types would help with understanding and make errors easier to track down:
fetchNearestFeatureTask =
stringInput
|> parseLatLng
: Result LatLng [ParseError]
|> Task.fromResult
|> Task.await \latlng -> fetchNearbyFeatures latlng mapService
: Task (List Feature) [ParseError, HTTPError]
|> Task.map nearestFeature
: Task ({feature: Feature, distance: F64}) _
This is consistent with how the REPL uses the : syntax to give the types of values, and not just variables:
» 42
42 : Num *
Related to this is specifying types alongside the definition of the variable, like in many other languages:
x : U64 = 2
f : (Num -> Str) = \(y : Num) -> Num.toStr y
Benefits:
In a long pipeline don't you feel that it is adding a lot of noise that most of the time you would want to look at? I feel like it makes the fundamental operations of the pipeline much harder to follow.
Sounds more like a use case for an the editor or an LSP. Then you could just highlight any sub expression and get the type.
It wouldn't be useful on every pipeline, but I often find it easier to understand what's happening at a high level by reading the types than by reading what functions are called. In that sense it helps cut through the noise of implementation details.
I hadn't thought about editors showing types. That does address part of the issue, but it's still nice to write typespecs down (as in this proposal and in general) as documentation, and so the typechecker can catch errors.
I should also acknowledge that this is yet another syntax proposal, because syntax proposals are easy to bikeshed, and the syntax of a language is not that important to its success. Most of this could be added later. The only backwards-incompatible thing that would have to be decided early is removing the existing syntax for having the types defined on a separate line from the value. So I'm happy to close this conversation if it's not useful to discuss right now.
I just listened to a recent Software Unscripted podcast (Conditional Cardinality with Joël Quenneville, at 6:02) where Richard mentioned that having separate type annotations was an explicit design choice that he liked, rather than copied without thinking about it from Elm.
So I'll mark this as Resolved now.
Sky Rose has marked this topic as resolved.
Last updated: Jun 16 2026 at 16:19 UTC