Marko Grdinić
Marko Grdinić

Reputation: 4062

Why is a curried parameter not defined in this CPS parser example?

Code:

type Result = string option
type Parser<'a> = string -> int -> ('a -> Result) -> ('a -> Result) -> Result
let win r = Some <| "Correct: " + r
let lose _ = None

let parse_a: Parser<char> = fun text i win_cps lose_cps ->
    let x = text.[i]
    if x = 'a' then win_cps x else lose_cps x

let parse_many: Parser<char> -> Parser<char list> = fun p text i win_cps lose_cps ->
    let rec loop: char list -> Parser<char list> = fun l text i _ _ ->
        let win = fun (l: char list) (r: char) -> loop (r:l) text i win_cps lose_cps
        let lose = fun (l: char list) (r: char) -> win_cps (r:l)
        p text (i+1) (win l) (lose l)
    loop [] text (i-1) win_cps lose_cps

parse_many parse_a "aaabc" 0 (fun r -> win (r |> System.String.Concat)) lose

The error: cps_parser_v0.fsx(12,59): error FS0039: The type 'l' is not defined

I want to make a functionally pure CPS parser in Haskell and am experimenting in F# first. If I really wanted to do this in F# I would use mutable state, but for now I am just wondering why this is not working? It looks to me that it can't remember partially applied parameters.

Upvotes: 2

Views: 50

Answers (1)

rmunn
rmunn

Reputation: 36678

You have a typo: (r:l) should be (r::l). The : operator means "is of type", i.e. r:l means that you're telling the compiler that r is of type l. The :: operator means "prepend this to the front of this list": r::l means "prepend r to the front of list l".

You've made this mistake in two places: loop (r:l) should be loop (r::l), and one line further down, win_cps (r:l) should be win_cps (r::l).

Upvotes: 5

Related Questions