# Understanding Parser Loop

**URL:** https://discourse.elm-lang.org/t/understanding-parser-loop/3279
**Category:** Learn
**Created:** [March 7, 2019, 6:42am UTC](https://discourse.elm-lang.org/t/understanding-parser-loop/3279 "2019-03-07T06:42:58Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![kfk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/kfk/32/1884_2.png) [@kfk](https://discourse.elm-lang.org/u/kfk)
#### Post date: [March 7, 2019, 6:42am UTC](https://discourse.elm-lang.org/t/understanding-parser-loop/3279/1 "2019-03-07T06:42:58Z")

</div>

I would like to have a parser that can transform a string "[1,2,3,4,5] into an elm List [1,2,3,4,5]

I want to user loop for this and I am getting somewhere with this great post: [https://korban.net/posts/elm/2018-09-07-introduction-elm-parser/](https://korban.net/posts/elm/2018-09-07-introduction-elm-parser/)

With that I was able to get here so far: [https://ellie-app.com/4V96cbjjrKta1](https://ellie-app.com/4V96cbjjrKta1)

So not exactly, but getting closer. Now unfortunately I cannot wrap my head around this part of the code:

```auto
stringHelp : List String -> Parser (Step (List String) (List String))
stringHelp nums =
    let
        checkNum numsSoFar num =
            if String.length num > 0 then
                Loop (num :: numsSoFar)

            else
                Done (List.reverse numsSoFar)
    in
    succeed (checkNum nums)
        |= (getChompedString <| chompWhile Char.isDigit)

```

The variables checkNum, numsSoFar and num don’t seem to be defined anywhere? How can I do String.length on num? I don’t have a definition of num before or inside the let closure.

```auto
        checkNum numsSoFar num =
            if String.length num > 0 then

```

I am sure I am missing something rather basic, pointing me to docs or tutorials to understand this would be a huge help too.

Edit. OK I understand let checkNum numsSoFar num now, basically checkNum is a function with arguments numSoFar and num. But I still struggle with num, where is that coming from? Also because after let we do a partial function call inside in without num?

---

<div class="post-metadata">

### Author: ![ilias](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/ilias/32/6_2.png) [@ilias](https://discourse.elm-lang.org/u/ilias)
#### Post date: [March 7, 2019, 8:27am UTC](https://discourse.elm-lang.org/t/understanding-parser-loop/3279/2 "2019-03-07T08:27:30Z")

</div>

This code:

```elm
stringHelp : List String -> Parser (Step (List String) (List String))
stringHelp nums =
    let
        checkNum numsSoFar num =
            if String.length num > 0 then
                Loop (num :: numsSoFar)

            else
                Done (List.reverse numsSoFar)
    in
    succeed (checkNum nums)
        |= (getChompedString <| chompWhile Char.isDigit)

```

Is equivalent to this code:

```elm
stringHelp : List String -> Parser (Step (List String) (List String))
stringHelp nums =
    succeed (checkNum nums)
        |= (getChompedString <| chompWhile Char.isDigit)

checkNum : List String -> String -> Parser.Step (List String) (List String)
checkNum numsSoFar num =
    if String.length num > 0 then
        Loop (num :: numsSoFar)

    else
        Done (List.reverse numsSoFar)

```

So indeed, `checkNum` is just a function, that takes two arguments. It is passed the `nums` that `stringHelp` receives as its first argument. The second argument is eventually produced through `(getChompedString <| chompWhile Char.isDigit)`.

The general pattern for a parser looks like this:

```elm
succeed someFunction -- function that uses/combines the things produced by the parser
  |= someParser -- provides the first argument
  |. otherParser -- parses something, but not used by the function
  |= yetAnotherParser -- provides the second argument

```

* * *

So, this whole `stringHelp` function is a function which

- receives a `List String` signifying a stack of things parsed so far
- returns a parser, which:
  - chomps a contiguous chunk of digits into a string
  - if the resulting string is empty, it says “okay, I’m done, nothing left to do” and succeeds with the stack reversed
  - if the resulting string is not empty, it says “okay, continuing!” and pushes the parsed string onto the stack.

---

<div class="post-metadata">

### Author: ![kfk](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/kfk/32/1884_2.png) [@kfk](https://discourse.elm-lang.org/u/kfk)
#### Post date: [March 7, 2019, 9:24pm UTC](https://discourse.elm-lang.org/t/understanding-parser-loop/3279/3 "2019-03-07T21:24:57Z")

</div>

Thank you. This was really helpful and I managed to implement my little parser! Now I can parse a sum “function” with “values” into a list:

```elm
module Main exposing (main)

import Browser
import Html exposing (Html, button, div, h2, input, text)
import Html.Attributes exposing (class, placeholder, value)
import Html.Events exposing (onClick, onInput)
import Parser exposing (..)

main =
    Html.text <|
        Debug.toString <|
            run stringParser "sum,2,3,3,4,5,1,2"

stringParser =
    loop [] stringHelp

stringHelp stmt =
    let
        f acc num =
            if String.length num > 0 then
                Loop (num :: acc)

            else
                Done (List.reverse acc)
    in
    oneOf
        [ succeed (f stmt)
            |= (keyword "sum" |> getChompedString)
        , succeed (f stmt)
            |. symbol ","
            |= (chompWhile Char.isDigit |> getChompedString)
        , succeed (f stmt)
            |= (chompWhile Char.isDigit |> getChompedString)
        ]

```

It’s interesting to notice that right now if any of the succeed break the pipeline the entire parser stops. So for instance if I do “sum,1,2,3,abc,4,5,6” I get only values “sum,1,2,3” because at “abc” the Char.isDigit breaks the pipeline flow.

Also, you are right the |= passes parameters to the function and that parameter must be a String. The reason it must be a string it’s because of this:

`if String.length num > 0 then`

Since we are doing the above, num must be a string, hence all the return values of |= must be of type string too. This means even with `|= keyword = "sum"` you must to `(keyword "sum" |> getChompedString)` otherwise you get a Parser () type and that is not playing well with the String.length num.

I would like to add types to this now. Instead of having:

`Ok ["sum","2","3","3","4","5","1","2"]`

I would like a structure like

`Ok Sum [2,3,3,4,5,1,2]`

So I can create a fairly simple AST to then compute the values in the list based on the function (Sum, Multiply, etc.).

I’ll continue working on this. Thanks again!

---

<div class="post-metadata">

### Author: ![system](https://canada1.discourse-cdn.com/flex035/uploads/elm_lang/original/1X/50a05e53677a2c3b47776d7abd0f113eb50193a1.png) [@system](https://discourse.elm-lang.org/u/system)
#### Post date: [March 17, 2019, 9:25pm UTC](https://discourse.elm-lang.org/t/understanding-parser-loop/3279/4 "2019-03-17T21:25:02Z")

</div>

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.
