Stream: beginners

Topic: Infer type for pipeline?


view this post on Zulip Jared Cone (Nov 07 2024 at 00:18):

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

view this post on Zulip Dan G Knutson (Nov 07 2024 at 00:21):

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

view this post on Zulip Dan G Knutson (Nov 07 2024 at 00:23):

or do you mean defining a type name in terms of that, the way TS typeof and related features work?

view this post on Zulip Brendan Hansknecht (Nov 07 2024 at 01:23):

Theoretically could be done with a dummy decoder that always gives zeroed/empty data

view this post on Zulip Jared Cone (Nov 07 2024 at 01:41):

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

view this post on Zulip Jared Cone (Nov 07 2024 at 01:45):

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

view this post on Zulip Brendan Hansknecht (Nov 07 2024 at 05:14):

I don't think you have to declare it. It just has to be decidable at compile time

view this post on Zulip Jared Cone (Nov 07 2024 at 06:19):

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

view this post on Zulip Ryan Barth (Nov 09 2024 at 07:49):

@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.

view this post on Zulip Jared Cone (Nov 09 2024 at 15:11):

Thanks!


Last updated: Jul 06 2025 at 12:14 UTC