I am trying to define a function that is similar to Lisp's apply. Here is my attempt:
type t =
| Str of string
| Int of int
let rec apply f args =
match args with
| (Str s)::xs -> apply (f s) xs
| (Int i)::xs -> apply (f i) xs
| [] -> f
(* Example 1 *)
let total = apply (fun x y z -> x + y + z)
[Int 1; Int 2; Int 3]
(* Example 2 *)
let () = apply (fun name age ->
Printf.printf "Name: %s\n" name;
Printf.printf "Age: %i\n" age)
[Str "Bob"; Int 99]
However, this fails to compile. The compiler gives this error message:
File "./myprog.ml", line 7, characters 25-30:
7 | | (Str s)::xs -> apply (f s) xs
^^^^^
Error: This expression has type 'a but an expression was expected of type
string -> 'a
The type variable 'a occurs inside string -> 'a
What is the meaning of this error message? How can I fix the problem and implement apply?
You cannot mix an untyped DSL for data:
type t =
| Int of int
| Float of float
and a shallow embedding (using OCaml functions as functions inside the DSL) for functions in apply
let rec apply f args =
match args with
| (Str s)::xs -> apply (f s) xs (* f is int -> 'a *)
| (Int i)::xs -> apply (f i) xs (* f is string -> 'a *)
| [] -> f (* f is 'a *)
The typechecker is complaining that if f has type 'a, f s cannot also have for type 'a since it would mean that f has simultaneously type string -> 'a and 'a (without using the recursive types flag).
And more generally, your function apply doesn't use f with a coherent type: sometimes it has type 'a, sometimes it has type int -> 'a, other times it would rather have type string -> 'a. In other words, it is not possible to write a type for apply
val apply: ??? (* (int|string) -> ... *) -> t list -> ???
You have to choose your poison.
Either go with a fully untyped DSL which contains functions, that can be applied:
type t =
| Int of int
| Float of float
| Fun of (t -> t)
exception Type_error
let rec apply f l = match f, l with
| x, [] -> f
| Fun f, a :: q -> apply (f a) q
| (Int _|Float _), _ :: _ -> raise Type_error
or use OCaml type system and define a well-typed list of arguments with a GADT:
type ('a,'b) t =
| Nil: ('a,'a) t
| Cons: 'a * ('b,'r) t -> ('a -> 'b,'r) t
let rec apply: type f r. f -> (f,r) t -> r = fun f l ->
match l with
| Nil -> f
| Cons (x,l) -> apply (f x) l
EDIT:
Using the GADT solution is quite direct since we are using usual OCaml type without much wrapping:
let three = apply (+) (Cons(1, Cons(2,Nil)))
(and we could use a heterogeneous list syntactic sugar to make this form even lighter syntactically)
The untyped DSL requires to build first a function in the DSL:
let plus = Fun(function
| Float _ | Fun _ -> raise Type_error
| Int x -> Fun(function
| Float _ | Fun _ -> raise Type_error
| Int y -> Int (x+y)
)
)
but once we have built the function, it is relatively straightforward:
let three = apply_dsl plus [Int 2; Int 1]
type t =
| Str of string
| Int of int
| Unit
let rec apply f args =
match args with
| x::xs -> apply (f x) xs
| [] -> f Unit
Let's go step by step:
line 1: apply : 'a -> 'b -> 'c (we don't know the types of f, args and apply's return type
line 2 and beginning of line 3: args : t list so apply : 'a -> t list -> 'c
rest of line 3: Since f s (s : string), f : string -> 'a but f t : f because apply (f s). This means that f contains f in its type, this is a buggy behaviour
It's actually buggy to call f on s and i because this means that f can take a string or an int, the compiler will not allow it.
And lastly, if args is empty, you return f so the return type of f is the type of f itself, another buggy part of this code.
Looking at your examples, a simple solution would be:
type t = Str of string | Int of int
let rec apply f acc args =
match args with x :: xs -> apply f (f acc x) xs | [] -> acc
(* Example 1 *)
let total =
apply
(fun acc x ->
match x with Int d -> d + acc | Str _ -> failwith "Type error")
0 [ Int 1; Int 2; Int 3 ]
(* Example 2 *)
let () =
apply
(fun () -> function
| Str name -> Printf.printf "Name: %s\n" name
| Int age -> Printf.printf "Age: %i\n" age)
() [ Str "Bob"; Int 99 ]
Since you know the type you want to work on, you don't need GADT shenanigans, just let f handle the pattern matching and work with an accumulator
Related
I was working on chapter 1 of Modern Compiler Implementation in ML by Andrew Appel and I decided to implement it in OCaml instead of SML. I'm new to OCaml and I came across a very frustrating problem. OCaml seems to think that the below function has the signature int * (int * 'a) -> 'a option.
let rec lookupTable = function
| name, (i, v) :: _ when name = i -> Some v
| name, (_, _) :: rest -> lookupTable (name, rest)
| _, [] -> None
But as far as I can tell, there should be nothing that suggests that the first element in the tuple is an int. This is a problem because when the lookupTable function down the line, the compiler complains that I am not passing it an integer. Perhaps I am missing something incredibly obvious, but it has been pretty mind-boggling. Here is the rest of the program
open Base
type id = string
type binop = Plus | Minus | Times | Div
type stm =
| CompoundStm of stm * stm
| AssignStm of id * exp
| PrintStm of exp list
and exp =
| IdExp of id
| NumExp of int
| OpExp of exp * binop * exp
| EseqExp of stm * exp
(* Returns the maximum number of arguments of any print
statement within any subexpression of a given statement *)
let rec maxargs s =
match s with
| CompoundStm (stm1, stm2) -> Int.max (maxargs stm1) (maxargs stm2)
| AssignStm (_, exp) -> maxargs_exp exp
(* Might be more nested expressions *)
| PrintStm exps -> Int.max (List.length exps) (maxargs_explist exps)
and maxargs_exp e = match e with EseqExp (stm, _) -> maxargs stm | _ -> 0
and maxargs_explist exps =
match exps with
| exp :: rest -> Int.max (maxargs_exp exp) (maxargs_explist rest)
| [] -> 0
type table = (id * int) list
let updateTable name value t : table = (name, value) :: t
let rec lookupTable = function
| name, (i, v) :: _ when name = i -> Some v
| name, (_, _) :: rest -> lookupTable (name, rest)
| _, [] -> None
exception UndefinedVariable of string
let rec interp s =
let t = [] in
interpStm s t
and interpStm s t =
match s with
| CompoundStm (stm1, stm2) -> interpStm stm2 (interpStm stm1 t)
| AssignStm (id, exp) ->
let v, t' = interpExp exp t in
updateTable id v t'
(* Might be more nested expressions *)
| PrintStm exps ->
let interpretAndPrint t e =
let v, t' = interpExp e t in
Stdio.print_endline (Int.to_string v);
t'
in
List.fold_left exps ~init:t ~f:interpretAndPrint
and interpExp e t =
match e with
| IdExp i -> (
match lookupTable (i, t) with
| Some v -> (v, t)
| None -> raise (UndefinedVariable i))
| NumExp i -> (i, t)
| OpExp (exp1, binop, exp2) ->
let exp1_val, t' = interpExp exp1 t in
let exp2_val, _ = interpExp exp2 t' in
let res =
match binop with
| Plus -> exp1_val + exp2_val
| Minus -> exp1_val - exp2_val
| Times -> exp1_val * exp2_val
| Div -> exp1_val / exp2_val
in
(res, t')
| EseqExp (s, e) -> interpExp e (interpStm s t)
Base defines = as int -> int -> bool, so when you have the expression name = i the compiler will infer them as ints.
You can access the polymorphic functions and operators through the Poly module, or use a type-specific operator by locally opening the relevant module, e.g. String.(name = i).
The reason Base does not expose polymorphic operators by default is briefly explained in the documentation's introduction:
The comparison operators exposed by the OCaml standard library are polymorphic:
What they implement is structural comparison of the runtime representation of values. Since these are often error-prone, i.e., they don't correspond to what the user expects, they are not exposed directly by Base.
There's also a performance-argument to be made, because the polymorphic/structural operators need to also inspect what kind of value it is at runtime in order to compare them correctly.
I have a list of (string * int) list elements and I need to find the biggest int element and return the corresponding(string * int) element.
I have something like this atm, but problem is, I think my approach is more of "typical programming"
let it = [] in
for x = 0 to length LIST - 1 do
let str = ((List.nth LIST x).string) in
let num = ((List.nth LIST x).int) in
let it = it # [num, str] in
let (str, num) = List.hd(List.rev it) in
[str, num]
What I tried to do is to loop through the list and add the string and int value in another list, then sort them, reverse it and then take the head, which should be the max int, then I need to return the pair in (string * int)
Your code is not a well-formed OCaml code. It highlights, however, some number of issues with your understanding of OCaml.
First of all, by default, values in OCaml are immutable. For example,
let x = 0 in
for i = 0 to 10 do
let x = x + 1 in
print_int x;
done
You will get 11111111111 as the output. This is because, during the loop, you are just computing every time the x+1 expression, where x is always 0 and you will always get 1 as the result. This is because, let x = <expr> in <body> is not changing the existing variable x but is creating a new variable x (shadowing any previous definitions) and make it available in the scope of the <body> expression.
Concerning your problem in general, it should be solved as a recursive function greatest_element, which has the following definition,
for an empty list [] it is undefined;
for a list of one element [x] is it is x;
otherwise, for a list of x::xs it is max x (greatest_element xs),
where max x y is x if it is greater or equal to y.
Finally, it looks like you have missed the first steps in OCaml and before solving this task you have to move back and to learn the basics. In particular, you have to learn how to call functions, bind variables, and in general what are the lexical conventions and syntax of the language. If you need pointers, feel free to ask.
First of all, it doesn't seem that you did any kind of sorting in
the code that you provided.
Assuming that your list is of type
(string * int) list then a possible to find the element with the
maximum integer using recursion:
let max_in_list list =
let rec auxiliary max_str max_int = function
| []
-> (max_str, max_int)
| (crt_str, crt_int)::tail when crt_int > max_int
-> auxiliary crt_str crt_int tail
| _::tail
-> auxiliary max_str max_int tail
in
match list with
| []
-> None
| (fst_str, fst_int)::tail
-> Some (auxiliary fst_str fst_int tail)
let check = max_in_list [("some", 1); ("string", 3); ("values", 2)]
You could write a generic maxBy function. This allows you to get the max of any list -
let rec maxBy f = function
| [] -> None
| [ x ] -> Some x
| x :: xs ->
match (maxBy f xs) with
| Some y when (f y) > (f x) -> Some y
| _ -> Some x
(* val maxBy : ('a -> 'b) -> 'a list -> 'a option = <fun> *)
let data = [("a", 3); ("b", 2); ("c", 6); ("d", 1)]
(* val data : (string * int) list = [("a", 3); ("b", 2); ("c", 6); ("d", 1)]*)
maxBy (fun (_, num) -> num) data
(* - : (string * int) option = Some ("c", 6) *)
maxBy (fun (str, _) -> str) data
(* - : (string * int) option = Some ("d", 1) *)
maxBy (fun x -> x) [3; 2; 6; 1]
(* - : int option = Some 6 *)
maxBy (fun x -> x) ["c"; "d"; "b"; "a"]
(* - : string option = Some "d" *)
maxBy (fun x -> x) []
(* - : 'a option = None *)
It can be fun to rewrite the same function in various ways. Here's another encoding -
let maxBy f list =
let rec loop r = function
| [] -> r
| x::xs when (f x) > (f r) -> loop x xs
| _::xs -> loop r xs
in
match list with
| [] -> None
| x::xs -> Some (loop x xs)
(* val maxBy : ('a -> 'b) -> 'a list -> 'a option = <fun> *)
I am learning F#. I have written custom fold function for list (with help here on StackOverflow). I am now trying to write foldback function say myOwnFoldBack. The expected output might be myOwnFoldBack (+) 0 [1; 2; 3 ] should return 6.
Here is my code for myOwnFold
let rec myOwnFoldf s0 =
function
| [] -> s0
| x::tail -> myOwnFoldf (f s0 x) tail
This works fine.
Here is code for myOwnFoldBack
let rec myOwnFoldBack f s0 =
function
| [] -> 0
| x::tail -> x f (myOwnFoldBackf tail)
The error I get is:
Type mismatch. Expecting a
'a
but given a
('b -> 'a -> int) list -> int
The resulting type would be infinite when unifying ''a' and '('b -> 'a -> int) list -> int'
I think I figured it out finally!
let rec myOwnFoldBack f s0 =
function
| [] -> s0
| x::tail -> f x (myOwnFoldBack f s0 tail)
So I have this exercise:
filter (fun x -> x = 0) [(1,0);(2,1);(3,0);(4,1)];;
result int list [1;3]
So basically you have to match your x in fun with the second number in list and if its the same you create new list with the first number.
My solution but is wrong
let rec filter f = function
| []->[]
| x::l -> if f=snd x then fst x :: filter f l else [];;
I get the following error when i want to try the code:
Error: This expression has type int but an expression was expected of
type
int -> bool
I can't reproduce the problem you report. Here's what I see when I try your code:
$ ocaml
OCaml version 4.02.1
# let rec filter f = function
| []->[]
| x::l -> if f=snd x then fst x :: filter f l else [] ;;
val filter : 'a -> ('b * 'a) list -> 'b list = <fun>
# filter 0 [(1,0); (2,1); (3,0)];;
- : int list = [1]
There are no errors, but it gets the wrong answer. That's what I would expect looking at your code.
The error that you are getting is saying that somewhere the compiler is expecting an int -> bool function, but you are giving it an int. The reason you get this error is because you have an equality (f = snd x), where f is of type int -> bool and snd x is of type int. both arguments given to the equality must be of the same type. Instead, what you want to do is simply branch on the result of applying f to the second element of x, such as:
let rec filter f = function
| []->[]
| x::l -> if f (snd x) then fst x :: filter f l else [];;
That said, I would recommend using pattern matching instead of fst and snd, such as:
let rec filter f l =
match l with
| [] -> []
| (x,y)::l -> if f y then x :: filter f l else filter f l
Note that f y will return something of type bool, which will then determine which branch to take.
Altough Matts answer is right. It's good to just reuse existing functions instead of writing a special from the ground up:
[(1,0);(2,1);(3,0);(4,1)]
|> List.filter (fun (_, x) -> x = 0)
|> List.map fst
I saw in the OCaml manual this example to use GADT for an AST with function application:
type _ term =
| Int : int -> int term
| Add : (int -> int -> int) term
| App : ('b -> 'a) term * 'b term -> 'a term
let rec eval : type a. a term -> a = function
| Int n -> n
| Add -> (fun x y -> x+y)
| App(f,x) -> (eval f) (eval x)
Is this the right way of representing function application for a language not supporting partial application?
Is there a way to make a GADT supporting function application with an arbitrary number of arguments?
Finally, is GADT a good way to represent a typed AST? Is there any alternative?
Well, partial eval already works here:
# eval (App(App(Add, Int 3),Int 4)) ;;
- : int = 7
# eval (App(Add, Int 3)) ;;
- : int -> int = <fun>
# eval (App(Add, Int 3)) 4 ;;
- : int = 7
What you don't have in this small gadt is abstraction (lambdas), but it's definitely possible to add it.
If you are interested in the topic, there is an abundant (academic) literature. This paper presents various encoding that supports partial evaluation.
There are also non-Gadt solutions, as shown in this paper.
In general, GADT are a very interesting way to represent evaluators. They tend to fall a bit short when you try to transform the AST for compilations (but there are ways).
Also, you have to keep in mind that you are encoding the type system of the language you are defining in your host language, which means that you need an encoding of the type feature you want. Sometimes, it's tricky.
Edit: A way to have a GADT not supporting partial eval is to have a special value type not containing functions and a "functional value" type with functions. Taking the simplest representation of the first paper, we can modify it that way:
type _ v =
| Int : int -> int v
| String : string -> string v
and _ vf =
| Base : 'a v -> ('a v) vf
| Fun : ('a vf -> 'b vf) -> ('a -> 'b) vf
and _ t =
| Val : 'a vf -> 'a t
| Lam : ('a vf -> 'b t) -> ('a -> 'b) t
| App : ('a -> 'b) t * 'a t -> 'b t
let get_val : type a . a v -> a = function
| Int i -> i
| String s -> s
let rec reduce : type a . a t -> a vf = function
| Val x -> x
| Lam f -> Fun (fun x -> reduce (f x))
| App (f, x) -> let Fun f = reduce f in f (reduce x)
let eval t =
let Base v = reduce t in get_val v
(* Perfectly defined expressions. *)
let f = Lam (fun x -> Lam (fun y -> Val x))
let t = App (f, Val (Base (Int 3)))
(* We can reduce t to a functional value. *)
let x = reduce t
(* But we can't eval it, it's a type error. *)
let y = eval t
(* HOF are authorized. *)
let app = Lam (fun f -> Lam (fun y -> App(Val f, Val y)))
You can make that arbitrarly more complicated, following your needs, the important property is that the 'a v type can't produce functions.