I have to define the signature tEXP of a functor which, starting from a module A with signature tARITH, constructs an abstract type representing expressions. This type of expressions will be named t.
the signature have to declare different operations to build an expression:
from a constant of type A.t (cst operation)
as the opposite of an expression (opp)
as an operation on two expressions (add and mul)
Finally, a compute operation will describe the evaluation of an expression to obtain its value (of type A.t).
I have written this so far :
module type tARITH = sig
type t
val zero : t
val one : t
val add : t -> t -> t
val mul : t -> t -> t
val opp : t -> t
val of_int : int -> t
val to_string : t -> string
end
module INT : tARITH = struct
type t = int
let zero = 0;;
let one =1;;
let add x y = x+y;;
let mul x y = x*y;;
let opp x = -x;;
let of_int x= x;;
let to_string x= string_of_int x;;
end ;;
type m3 = Zero | Un | Deux
module M3:tARITH = struct
type t = m3
let zero = Zero;;
let one = Un;;
let add m n = if m=Zero && n=Zero || n=Un && m=Deux || m=Un && n=Deux then Zero
else if m=Deux && n=Zero || m=Un && n=Un || m=Zero && n=Deux then Deux
else Un;;
let mul m n = if m=Deux && n=Deux || m=Un && n=Un then Un
else if m=Deux && n=Un || n=Deux && m=Un then Deux
else Zero;;
let opp m = match m with
|Zero->Zero
|Un->Deux
|Deux->Un;;
let of_int m = match (m mod 3) with
|0->Zero
|1->Un
|2->Deux
|(-1)->opp Un
|(-2)->opp Deux
|_->Zero;;
let to_string x = match x with
|Zero->"0"
|Un->"1"
|Deux->"2" ;;
end;;
and here the signature of tEXP :
module type tEXP =
sig
type t = Constante of m3 | Somme of t*t | Produit of t*t
val cst t -> t;;
val opp x -> t ;;
val add x -> y -> t
val mul x -> y -> t
val compute x -> A.x;;
end ;;
module EXP = functor (A: tARITH)-> struct
type t = Constante of m3 | Somme of t*t | Produit of t*t
let cst x = x;;
let opp x = match x with
|Constante(x) -> x
|Constante(x)-> x
|Somme(x,y)-> A.plus (calculer x) (calculer y)
|Produit(x,y)-> A.mult (calculer x) (calculer y) ;;
let add x y = A.plus (calculer x) (calculer y);;
let mul x y = A.mul (calculer x) (calculer y) ;;
let compute x = A.x;;
end;;
I get an error at "sig" and the first "x", I don't really know why.
Thank you for your help. Here is the final answer:
module type tEXP = functor (A : tARITH) -> sig
type t
val cst : A.t -> t
val opp : t -> t
val add : t -> t -> t
val mul : t -> t -> t
val compute : t -> A.t
end;;
module EXP = functor (A : tARITH) -> struct
type t = Const of A.t | Opp of t | Add of t*t | Mul of t*t
let cst c = Const (c)
let add ex1 ex2 = Add (ex1, ex2)
let opp exp = Opp (exp)
let mul ex1 ex2 = Mul (ex1, ex2)
let rec compute expr = match expr with
Const (c) -> c
| Opp (e) -> A.opp (compute e)
| Add(e1, e2) -> A.add (compute e1) (compute e2)
| Mul(e1, e2) -> A.mul (compute e1) (compute e2)
end;;
I was wondering how could I achieve the following:
have all the "business logic" in a file
have a main.ml that uses that business logic
Business logic:
type point = {x:float; y:float;}
let pi_known = 3.141592653589793238462643383279502884197169399375105820974944592307816406286
let percentage_error pi_estimated =
((pi_known -. pi_estimated) /. pi_known) *. 100.0
let pi_and_error pi error =
Printf.sprintf "Pi's value :: %.10f Error rate :: %.10f %.%" pi error
let point_to_string { x = x; y = y } =
Printf.sprintf "%.2f %.2f" x y
let gen_point xr yr =
{x=xr; y=yr}
let distance_between_points p q =
(p.x -. q.x) *. (p.x -. q.x) +. (p.y -. q.y) *. (p.y -. q.y)
let distance_from_origin c =
distance_between_points c (gen_point 0.0 0.0)
let count_within ~counter:n =
let rec count_within_aux ~counter:n ~within:m =
match n, m with
| 0, m -> m
| n, m ->
let cc = gen_point (Random.float 1.0) (Random.float 1.0) in
let dist = distance_from_origin cc in
match dist with
| dist when dist <= 1.0 -> count_within_aux ~counter:(n - 1) ~within:(m + 1)
| dist when dist > 1.0 -> count_within_aux ~counter:(n - 1) ~within:m
| _ -> 0 in
count_within_aux ~counter:n ~within:0
let count_within_stepping ~counter:n ~stepping:s =
let rec count_within_stepping_aux ~counter:n ~within:m ~acc:acc =
match n, m, acc with
| n, m, acc when n <= 0 -> m
| n, m, acc ->
let c = count_within s in
let pi = ((float_of_int m) /. (float_of_int acc)) *. 4.0 in
let r = percentage_error pi in
print_endline (pi_and_error pi r);
count_within_stepping_aux ~counter:(n-s) ~within:(m+c) ~acc:(acc+s) in
count_within_stepping_aux ~counter:n ~within:0 ~acc:0
pi.mli:
(*
* Point in a two-dimensional Euclidean space
*)
type point = {x:float; y:float;}
val point_to_string : point -> string
val gen_point : float -> float -> point
(*
* 'Euclidean distance or Euclidean metric is the "ordinary" straight-line distance between
* two points in Euclidean space. With this distance, Euclidean space becomes a metric space.
* The associated norm is called the Euclidean norm.
* Older literature refers to the metric as Pythagorean metric.'
* https://en.wikipedia.org/wiki/Euclidean_distance
*)
val distance_between_points : point -> point -> float
val distance_from_origin : point -> float
val count_within : counter:int -> int
val count_within_stepping : counter:int -> stepping:int -> int
val percentage_error : float -> float
val pi_and_error : float -> float -> string
main.ml:
let main () =
Random.self_init();
let num_iter = Sys.argv.(1) in
let n = int_of_string num_iter in
print_endline ("Number of iterations :: " ^ num_iter);
let pi_estimated = ((float_of_int (Pi.count_within_stepping n (n / 20))) /. (float_of_int n)) *. 4.0 in
let r = Pi.percentage_error pi_estimated in
print_endline (Pi.pi_and_error pi_estimated r)
let () =
main ()
_oasis:
Name: Pi
Version: 0.1
Synopsis: Nope
Authors:
Istvan <istvan#mail.tld>
License: MIT
Homepage: http://0.0.0.0
OASISFormat: 0.4
BuildTools: ocamlbuild
Plugins: META (0.4), DevFiles (0.4)
Executable "pi"
Path: src
MainIs: main.ml
CompiledObject: best
BuildDepends:
str,unix
Unfortunatelly when I compile this and run it it returns nothing while if I merge main.ml and pi.ml it works as expected. What am I missing?
UPDTE:
After adding the mli file to the project and changing main.ml as it was suggested by #gallais it works as expected.
It turns out that mli files are necessary for using modules. Having src/x.ml and src/x.mli is required. If these files are present X can be referenced from main.ml.
i'm trying to write an interpreter in Ocaml but I do not know resolve the error in this program:
SYNTAX
type ide = string
type exp =
| Eint of int
| Ebool of bool
| Den of ide
| Sum of exp * exp
| Diff of exp * exp
| Prod of exp * exp
| Eq of exp * exp
| Minus of exp
| Iszero of exp
| Or of exp * exp
| And of exp * exp
| Not of exp
| Ifthenelse of exp * exp * exp
| Let of ide * exp * exp
| Fun of ide * exp
| Apply of exp * exp
| Letrec of ide * ide * exp * exp
| Etup of tuple (*Tupla come espressione*)
| Pipe of tuple (*Concatenazione di funzioni*)
| ManyTimes of int * exp (*Esecuzione iterata di una funzione*)
and tuple =
| Nil (*Tupla vuota*)
| Seq of exp * tuple (*Tupla di espressioni*)
;;
SEMANTIC
type eval=
| Int of int
| Bool of bool
| Unbound
| RecFunVal of ide * ide * exp * eval env
| Funval of efun
| ValTup of etuple
and efun = ide * exp * eval env
and etuple =
| Nil
| Seq of eval * etuple
;;
RUN-TIME SUPPORT
| Fun(i,a) -> Funval(i,a,r)
| Letrec(f, i, fBody, letBody) ->
let benv = bind(r, f, (RecFunVal(f, i, fBody, r)))
in sem(letBody, benv)
| Etup(tup) -> (match tup with
| Seq(ex1, tupla) ->
let evex1 = sem(ex1, r) in
let ValTup(etupla) = sem(Etup(tupla), r) in
ValTup(Seq(evex1, etupla))
| Nil -> ValTup(Nil))
| Apply(Den f, arg1) ->
(let fclosure= sem(Den f, r) in
match fclosure with
| Funval(arg, fbody, fDecEnv) ->
sem(fbody, bind(fDecEnv, arg, sem(arg1, r)))
| RecFunVal(f, arg, fbody, fDecEnv) ->
let aVal= sem(arg1, r) in
let rEnv= bind(fDecEnv, f, fclosure) in
let aEnv= bind(rEnv, arg, aVal) in
sem(fbody, aEnv)
| _ -> failwith("non functional value"))
| Apply(Pipe tup, arg) -> applyPipe tup arg r
| Apply(_,_) -> failwith("not function")
and applyPipe tup argo r = match tup with
| Seq(Den f, tupla) ->
applyPipe tupla (Apply(Den f,argo)) r
| Seq(Pipe(tuplaP),tupla) ->
let appf = applyPipe tuplaP argo r in
applyPipe tupla appf r (**)
| Nil -> sem(argo,r)
| _ -> failwith("Not a valid Pipe")
;;
The error is on the line (***) : "the variant type tuple has no constructor Pipe"
How can I solve it?
The compiler expects the first argument of applyPipe to have type tuple. On the line (***) the applyPipe is applied to the value Pipe(tupla) which has type exp.
HI I have the following define type and try to eval the function as example:
let evn =[("z1",Int 0);("x",Int 1);("y",Int 2);("z",Int 3);("z1",Int 4)];;
val evn : (string * Nano.value) list = [("z1", Int 0); ("x", Int 1); ("y", Int 2); ("z", Int 3); ("z1", Int 4)]
# let e1 =Bin(Bin(Var "x",Plus,Var "y"), Minus, Bin(Var "z",Plus,Var "z1"));;
val e1 : Nano.expr = Bin (Bin (Var "x", Plus, Var "y"), Minus, Bin (Var "z", Plus, Var "z1"))
# eval (evn,e1);;
- : Nano.value = Int 0
# eval (evn,Var "p");;
Exception: Nano.MLFailure "Variable not bound: p".
somehow i got a erros in the second bin match in the eval function saying :
This pattern matches values of type expr
but a pattern was expected which matches values of type
int option * int option
type binop = Plus | Minus | Mul | Div
type expr = Const of int
| Var of string
| Bin of expr * binop * expr
type value = Int of int
type env = (string * value) list
here is the programs:
exception MLFailure of string
type binop =
Plus
| Minus
| Mul
| Div
| Eq
| Ne
| Lt
| Le
| And
| Or
| Cons
type expr =
Const of int
| True
| False
| NilExpr
| Var of string
| Bin of expr * binop * expr
| If of expr * expr * expr
| Let of string * expr * expr
| App of expr * expr
| Fun of string * expr
| Letrec of string * expr * expr
type value =
Int of int
| Bool of bool
| Closure of env * string option * string * expr
| Nil
| Pair of value * value
and env = (string * value) list
let binopToString op =
match op with
Plus -> "+"
| Minus -> "-"
| Mul -> "*"
| Div -> "/"
| Eq -> "="
| Ne -> "!="
| Lt -> "<"
| Le -> "<="
| And -> "&&"
| Or -> "||"
| Cons -> "::"
let rec valueToString v =
match v with
Int i ->
Printf.sprintf "%d" i
| Bool b ->
Printf.sprintf "%b" b
| Closure (evn,fo,x,e) ->
let fs = match fo with None -> "Anon" | Some fs -> fs in
Printf.sprintf "{%s,%s,%s,%s}" (envToString evn) fs x (exprToString e)
| Pair (v1,v2) ->
Printf.sprintf "(%s::%s)" (valueToString v1) (valueToString v2)
| Nil ->
"[]"
and envToString evn =
let xs = List.map (fun (x,v) -> Printf.sprintf "%s:%s" x (valueToString v)) evn in
"["^(String.concat ";" xs)^"]"
and exprToString e =
match e with
Const i ->
Printf.sprintf "%d" i
| True ->
"true"
| False ->
"false"
| Var x ->
x
| Bin (e1,op,e2) ->
Printf.sprintf "%s %s %s"
(exprToString e1) (binopToString op) (exprToString e2)
| If (e1,e2,e3) ->
Printf.sprintf "if %s then %s else %s"
(exprToString e1) (exprToString e2) (exprToString e3)
| Let (x,e1,e2) ->
Printf.sprintf "let %s = %s in \n %s"
x (exprToString e1) (exprToString e2)
| App (e1,e2) ->
Printf.sprintf "(%s %s)" (exprToString e1) (exprToString e2)
| Fun (x,e) ->
Printf.sprintf "fun %s -> %s" x (exprToString e)
| Letrec (x,e1,e2) ->
Printf.sprintf "let rec %s = %s in \n %s"
x (exprToString e1) (exprToString e2)
let rec fold f base args =
match args with [] -> base
| h::t -> fold f (f(base,h)) t
let listAssoc (k,l) =
fold (fun (r,(t,v)) -> if r = None && k=t then Some v else r) None l
let lookup (x,evn) =
let n = listAssoc (x,evn) in
match n with
| None -> raise (MLFailure x)
| Some x -> x
let rec eval (evn,e) = match e with
| Const i -> Some i
| Var v -> lookup (v,evn)
| Bin(e1, Plus, e2) -> match (eval (evn,e1), eval (evn,e2)) with
| (Some a, Some b) -> Some (a + b)
| (Some c, None) -> raise (MLFailure c)
| (None, Some a) -> raise (MLFailure a)
(here is the where the erro causing *)
| Bin(e1, Div, e2) -> match (eval (evn,e1), eval (evn,e2)) with
| (Some a, Some b) -> Some (a / b)
| (Some c, None) -> raise (MLFailure c)
| (None, Some a) -> raise (MLFailure a)
| Bin(e1, Minus, e2) -> match (eval (evn,e1), eval (evn,e2)) with
| (Some a, Some b) -> Some (a - b)
| (Some c, None) -> raise (MLFailure c)
| (None, Some a) -> raise (MLFailure a)
| Bin(e1, Mul, e2) -> match (eval (evn,e1), eval (evn,e2)) with
| (Some a, Some b) -> Some (a * b)
| (Some c, None) -> raise (MLFailure c)
| (None, Some a) -> raise (MLFailure a)
Be careful, with nested match-with do not forget to add begin-end statements. That's why you have this error.
let rec eval (evn,e) = match e with
| Const i -> Some i
| Var v -> lookup (v,evn)
| Bin(e1, Plus, e2) ->
begin match (eval (evn,e1), eval (evn,e2)) with
| (Some a, Some b) -> Some (a + b)
| (Some c, None) -> raise (MLFailure c)
| (None, Some a) -> raise (MLFailure a)
end
| Bin(e1, Div, e2) ->
begin match (eval (evn,e1), eval (evn,e2)) with
| (Some a, Some b) -> Some (a / b)
| (Some c, None) -> raise (MLFailure c)
| (None, Some a) -> raise (MLFailure a)
end
| Bin(e1, Minus, e2) ->
begin match (eval (evn,e1), eval (evn,e2)) with
| (Some a, Some b) -> Some (a - b)
| (Some c, None) -> raise (MLFailure c)
| (None, Some a) -> raise (MLFailure a)
end
| Bin(e1, Mul, e2) ->
begin match (eval (evn,e1), eval (evn,e2)) with
| (Some a, Some b) -> Some (a * b)
| (Some c, None) -> raise (MLFailure c)
| (None, Some a) -> raise (MLFailure a)
end
If you don't do this, it's like you wrote as follow:
let rec eval (evn,e) = match e with
| Const i -> Some i
| Var v -> lookup (v,evn)
| Bin(e1, Plus, e2) -> match (eval (evn,e1), eval (evn,e2)) with
| (Some a, Some b) -> Some (a + b)
| (Some c, None) -> raise (MLFailure c)
| (None, Some a) -> raise (MLFailure a)
| Bin(e1, Div, e2) -> match (eval (evn,e1), eval (evn,e2)) with
| (Some a, Some b) -> Some (a / b)
| (Some c, None) -> raise (MLFailure c)
| (None, Some a) -> raise (MLFailure a)
| Bin(e1, Minus, e2) -> (* ... *)
Hi I am writing an extraction from Coq to Ocaml, I would like to convert type:
positive --> int32
N -> int32
but I want to keep type Z is int
Here is the code I am doing to extract these conditions:
Require Import ZArith NArith.
Require Import ExtrOcamlBasic.
(* Mapping of [positive], [N], [Z] into [int32]. *)
Extract Inductive positive => int32
[ "(fun p-> let two = Int32.add Int32.one Int32.one in
Int32.add Int32.one (Int32.mul two p))"
"(fun p->
let two = Int32.add Int32.one Int32.one in Int32.mul two p)" "Int32.one" ]
"(fun f2p1 f2p f1 p -> let two = Int32.add Int32.one Int32.one in
if p <= Int32.one then f1 () else if Int32.rem p two = Int32.zero then
f2p (Int32.div p two) else f2p1 (Int32.div p two))".
Extract Inductive N => int32 [ "Int32.zero" "" ]
"(fun f0 fp n -> if n=Int32.zero then f0 () else fp n)".
Extract Inductive Z => int [ "0" "" "(~-)" ]
"(fun f0 fp fn z -> if z=0 then f0 () else if z>0 then fp z else fn (-z))".
I cannot do it to keep Z -> int because the definition of Z in Coq's library (BinInt.v)
Inductive Z : Set :=
| Z0 : Z
| Zpos : positive -> Z
| Zneg : positive -> Z.
I got an error: (function coq_Zdouble_plus_one)
File "BinInt.ml", line 38, characters 4-5:
Error: This expression has type int but an expression was expected of type
int32
BinInt.ml
open BinPos
open Datatypes
(** val coq_Z_rect :
'a1 -> (int32 -> 'a1) -> (int32 -> 'a1) -> int -> 'a1 **)
let coq_Z_rect f f0 f1 z =
(fun f0 fp fn z -> if z=0 then f0 () else if z>0 then fp z else fn (-z))
(fun _ ->
f)
(fun x ->
f0 x)
(fun x ->
f1 x)
z
(** val coq_Z_rec : 'a1 -> (int32 -> 'a1) -> (int32 -> 'a1) -> int -> 'a1 **)
let coq_Z_rec f f0 f1 z =
(fun f0 fp fn z -> if z=0 then f0 () else if z>0 then fp z else fn (-z))
(fun _ ->
f)
(fun x ->
f0 x)
(fun x ->
f1 x)
z
(** val coq_Zdouble_plus_one : int -> int **)
let coq_Zdouble_plus_one x =
(fun f0 fp fn z -> if z=0 then f0 () else if z>0 then fp z else fn (-z))
(fun _ ->
Int32.one)
(fun p ->
((fun p-> let two = Int32.add Int32.one Int32.one in
Int32.add Int32.one (Int32.mul two p))
p))
(fun p -> (~-)
(coq_Pdouble_minus_one p))
x
If I extract Z -> int32, it is Ok, but it is not what I want.
Your problem is that Z is internally built upon positive.
Inductive Z : Set := Z0 : Z
| Zpos : positive -> Z
| Zneg : positive -> Z
.
This means that whenever you get a Z, you're really getting a positive and some extra info.
If you really want to use different types for Z and positive, you'll have to insert conversion functions between int and int32. You might be able to do that with the extraction feature, but I'm not sure how – or even if – that's possible.
Another problem I see is that code inside a match on Zs will get positives to work with, meaning that you'll be constantly converting between the types and losing any extra precision one of the types might have over the other. If at all possible, I'd use the same type for both.