Reputation: 13
I'm trying to write a simpler parser in OCaml but I have run into a problem I can't get past. I have simplified the code to a bare minimum example, which gives me the same error:
I want to write a function in OCaml that takes in a list of integers and outputs a list of strings.
The rules are that if there are two 1
s in a row then it outputs "eleven"
, if there is only one 1
it outputs "one"
and for any other number it outputs "other"
. This python code does the job:
def convert(numbers, names):
if len(numbers) == 0:
return names
n = numbers.pop(0)
if n == 1:
if len(numbers) > 0 and numbers[0] == 1:
numbers.pop(0)
names.append("eleven")
else:
names.append("one")
else:
names.append("other")
return convert(numbers, names)
convert([1, 1, 2, 1, 3, 1], [])
# -> ['eleven', 'other', 'one', 'other', 'one']
My attempt in OCaml is this:
let rec convert (numbers : int list) (names : string list) = function
| [] -> List.rev names
| 1 :: 1 :: t -> convert t ("eleven" :: names)
| 1 :: t -> convert t ("one" :: names)
| _ :: t -> convert t ("other" :: names)
;;
convert [1; 1; 2; 3] [];;
What I think will happen is convert
will call itself recursively: the list of integers will be get smaller and the list
of strings bigger until there are no more integers left:
convert [1; 1; 2; 1; 3; 1] []
-> convert [2; 1; 3; 1] ["eleven"]
-> convert [1; 3; 1] ["other"; "eleven"]
-> convert [3; 1] ["one"; "other"; "eleven"]
-> convert [1] ["other"; "one"; "other"; "eleven"]
-> convert [] ["one"; "other"; "one"; "other"; "eleven"]
-> ["eleven"; "other"; "one"; "other"; "one"]
But what actually happens is a compilation error:
Error: This expression has type int list -> string list
but an expression was expected of type string list
highlighting the text convert t ("eleven" :: names)
What's going on here? I don't understand why this doesn't work.
Upvotes: 1
Views: 425
Reputation: 29106
function | ...
is actually short-hand for fun x -> match x with | ...
. That is:
let convert numbers names = function
| ...
is equivalent to
let convert numbers names something_else =
match something_else with
| ...
Your convert
function therefore expects three arguments, and convert t ("eleven" :: names)
returns a function int list -> string list
rather than just a string list
as inferred from the first branch.
Replace function
with match numbers with
to have it compile:
let rec convert (numbers : int list) (names : string list) =
match numbers with
| [] -> List.rev names
| 1 :: 1 :: t -> convert t ("eleven" :: names)
| 1 :: t -> convert t ("one" :: names)
| _ :: t -> convert t ("other" :: names)
;;
convert [1; 1; 2; 3] [];;
Upvotes: 5