I think the answer will be no, but thought I'd check. For the example code below, is there some way I can have Roc infer a type based on the functions that it gets fed into? Like in the example below, somehow have Roc make ???
be a thing that has width and height fields?
setWidth = \data ->
{ data & width : 5 }
setHeight = \data ->
{ data & height : 10 }
data =
???
|> setWidth
|> setHeight
I think it'll work for functions even if it doesn't work for constants (tweaked to dodge the shadowing police):
setWidth = \d ->
{ d & width: 5 }
setHeight = \d ->
{ d & height: 10 }
data : _ -> _
data = \arg ->
arg
|> setWidth
|> setHeight
or do you mean defining a type name in terms of that, the way TS typeof
and related features work?
Theoretically could be done with a dummy decoder that always gives zeroed/empty data
Dan G Knutson said:
I think it'll work for functions even if it doesn't work for constants (tweaked to dodge the shadowing police):
setWidth = \d -> { d & width: 5 } setHeight = \d -> { d & height: 10 } data : _ -> _ data = \arg -> arg |> setWidth |> setHeight
In that example, whoever calls the data function still has to declare the thing they are passing in
Dummy decoder may work. IIRC you have to declare the type you are assigning decode to... not sure what it does if you don't
I don't think you have to declare it. It just has to be decidable at compile time
I'm having trouble making a dummy decoder. Running into a compiler crash:
DummyDecoder := {}
implements [
DecoderFormatting {
u8: decodeU8,
u16: decodeU16,
u32: decodeU32,
u64: decodeU64,
u128: decodeU128,
i8: decodeI8,
i16: decodeI16,
i32: decodeI32,
i64: decodeI64,
i128: decodeI128,
f32: decodeF32,
f64: decodeF64,
dec: decodeDec,
bool: decodeBool,
string: decodeString,
list: decodeList,
record: decodeRecord,
tuple: decodeTuple,
},
]
decodeU8 = Decode.custom \_, @DummyDecoder _ -> { result: Err TooShort, rest: [] }
decodeU16 = Decode.custom \_, @DummyDecoder _ -> { result: Err TooShort, rest: [] }
decodeU32 = Decode.custom \_, @DummyDecoder _ -> { result: Err TooShort, rest: [] }
decodeU64 = Decode.custom \_, @DummyDecoder _ -> { result: Err TooShort, rest: [] }
decodeU128 = Decode.custom \_, @DummyDecoder _ -> { result: Err TooShort, rest: [] }
decodeI8 = Decode.custom \_, @DummyDecoder _ -> { result: Err TooShort, rest: [] }
decodeI16 = Decode.custom \_, @DummyDecoder _ -> { result: Err TooShort, rest: [] }
decodeI32 = Decode.custom \_, @DummyDecoder _ -> { result: Err TooShort, rest: [] }
decodeI64 = Decode.custom \_, @DummyDecoder _ -> { result: Err TooShort, rest: [] }
decodeI128 = Decode.custom \_, @DummyDecoder _ -> { result: Err TooShort, rest: [] }
decodeF32 = Decode.custom \_, @DummyDecoder _ -> { result: Err TooShort, rest: [] }
decodeF64 = Decode.custom \_, @DummyDecoder _ ->{ result: Err TooShort, rest: [] }
decodeDec = Decode.custom \_, @DummyDecoder _ -> { result: Err TooShort, rest: [] }
decodeBool = Decode.custom \_, @DummyDecoder _ -> { result: Err TooShort, rest: [] }
decodeString = Decode.custom \_, @DummyDecoder _ -> { result: Err TooShort, rest: [] }
decodeList = \_ -> Decode.custom \_, @DummyDecoder _ -> { result: Err TooShort, rest: [] }
decodeRecord = \_, _, _ -> Decode.custom \_, @DummyDecoder _ -> { result: Err TooShort, rest: [] }
decodeTuple = \_, _, _ -> Decode.custom \_, @DummyDecoder _ -> { result: Err TooShort, rest: [] }
thread '<unnamed>' panicked at crates/compiler/solve/src/specialize.rs:863:25:
lambda set region not resolved: (`17.IdentId(26)`, MemberSpecializationInfo { _phase: PhantomData<roc_can::abilities::Resolved>, symbol: `17.IdentId(26)`, specialization_lambda_sets: VecMap { keys: [3, 1], values: [494, 502] } })
stack backtrace:
0: rust_begin_unwind
1: core::panicking::panic_fmt
2: roc_solve::specialize::compact_lambda_sets_of_vars
3: roc_solve::solve::solve
4: roc_solve::solve::run
5: roc_solve::module::run_solve
6: roc_load_internal::file::run_solve_solve
7: roc_load_internal::file::run_task
@Jared Cone I was just working on a decoder and hit this issue a bunch as well. A workaround I found was to comment out some of the registered definitions in the DecoderFormatting
block. When you do comment out the line causing the issue. The compile will give you an error about the missing difinitions, but it will also emit an error about one of the members that you can fix.
In this case since it is all dummy definitions I suspect it is the decodeRecord
/ decodeTuple
definitions. The compiler does not seem to like when there is no narrowing of the type information in those 2 declarations in particular. I find you can keep the dummies if you explicitly type the definitions. If you want to steal the type definitions I had ones that worked here.
Thanks!
Last updated: Jul 06 2025 at 12:14 UTC