roc-lang / roc

A fast, friendly, functional language.
https://roc-lang.org
Universal Permissive License v1.0
4.19k stars 301 forks source link

add `List.splitIf` builtin #4176

Open bhansconnect opened 2 years ago

bhansconnect commented 2 years ago

Not sure about naming. Also, this may not be important if we have a nice parsing library to use, but looking at day 4, I would like to first split the string by new line, then split the produced list by empty lines. I feel that some sort of split function that uses a predicate would be quite useful for lists in general. Of course, this can be implemented with List.walk if needed.

CC: @ayazhafiz since he is looking into adding some sort of parsing library that may solve this issue in a nicer way and makes adding this unnecessary.

ayazhafiz commented 2 years ago

Yeah I think this is better done by a parsing library and not needed as a builtin. Here's what a parser for day 4 with a combinator I'm working on ends up looking like

Square : [Marked, Sq U64]
Board : List (List Square)
Input : [Bingo (List U64) (List Board)]

parseInput : _ -> Result Input _
parseInput = \input ->
    u64 = digits |> map Num.toU64
    square = u64 |> map Sq

    parseSepSquare =
        (opt spaces)
        |> dropBefore square

    parseBoardLine =
        oneOrMore parseSepSquare
        |> dropAfter newline

    parseBoard =
        newline
        |> dropBefore (many parseBoardLine)

    parseNumbers =
        u64
        |> sepBy (codeunit (Num.toU8 ','))
        |> dropAfter newline

    parseLines =
        const (\nums -> \boards -> Bingo nums boards)
        |> apply parseNumbers
        |> apply (many parseBoard)

    when parseBytes parseLines input is
        Ok a -> Ok a
        Err (Msg s) -> Err (Msg s)
bhansconnect commented 2 years ago

My one concern with a solution like the one you wrote is that it is complex. I feel like a new user would not be able to think up something like that without many examples and some simplification. Using step by step direct splitting and cutting things up is much easier to think through.

ayazhafiz commented 2 years ago

My concern is also a bit with bloating the standard library. I don't feel terribly strongly, but IMO the use case is relatively niche (parsers), and as you mentioned, it can be implemented with List.walk. Moreover a walk-based (or other) implementation is likely to be much more efficient than splitIf, as it avoids intermediate lists.

On Mon, Oct 3, 2022 at 11:02 AM Brendan Hansknecht @.***> wrote:

My one concern with a solution like the one you wrote is that it is complex. I feel like a new user would not be able to think up something like that without many examples and some simplification. Using step by step direct splitting and cutting things up is much easier to think through.

— Reply to this email directly, view it on GitHub https://github.com/roc-lang/roc/issues/4176#issuecomment-1265683876, or unsubscribe https://github.com/notifications/unsubscribe-auth/AE6GL6TFZK6LWSLWKRAKQUDWBL7P7ANCNFSM6AAAAAAQ3WJMXM . You are receiving this because you were mentioned.Message ID: @.***>

bhansconnect commented 2 years ago

Yeah, i don't know the scope of how large the stardard librsry should get/what is normal in a functional language.

Though performance should be fine with seamless slices.