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.
Related
Lets say we have a record which defines students:
type student = {
name : string;
age : int;
grades : (float) list;
}
And safe them in a list like this:
let studentlist = [ {name="alex"; age=7; grades=[1.;2.;3.]} ;
{name="bianca"; age=6; grades=[1.;1.;2.]} ];;
My aim is to compute the grade average of a special student which I choose per age, I select the student with the function search:
let search a lst = List.find( fun {age;_} -> a = age)lst
And compute the average with the help-functions , named sum, length and finally avr :
let rec sum lst =
match lst with
| [] -> 0.0
| h :: t -> h +. sum t
let length lst = float_of_int (List.length lst);;
let avr lst = sum lst /. length lst;;
I don't know how to combine those functions to compute the average properly!
Most of what you've done seems to work. For instance, search works.
utop # search 7 studentlist;;
- : student = {name = "alex"; age = 7; grades = [1.; 2.; 3.]}
If you want to access the grades field of that record, use . for record access.
utop # (search 7 studentlist).grades;;
- : float list = [1.; 2.; 3.]
Now that you have a list of float values, finding the sum or average of them should be easy by passing that value as an argument to the relevant function you've already defined.
Bear in mind that when you use List.find in search, if you search for an age that is not present, you will get a Not_found exception that you will want to handle.
As an aside, note that your avr function iterates over the list twice. Once to compute the sum, and ocne to compute the length.
It is possible to computer the sum, the length, and the average in a single pass. We can use a fold to do this. First off, we can define a basic left fold:
let rec foldl f init lst =
match lst with
| [] -> init
| x::xs -> foldl f (f init x) xs
Consider using this to compute the length of a list:
foldl (fun i _ -> i + 1) 0 [1.; 2.; 3.]
When evaluated:
foldl (fun i _ -> i + 1) 0 [1.; 2.; 3.]
foldl (fun i _ -> i + 1) (0 + 1) [2.; 3.]
foldl (fun i _ -> i + 1) (1 + 1) [3.]
foldl (fun i _ -> i + 1) (2 + 1) []
3
But we can pass a tuple of values to foldl, building up the length, sum, and average as we go.
utop # let (len, sum, avg) = foldl
(fun (len, sum, avg) x ->
let sum = sum +. x in
let len = len + 1 in
let flen = float_of_int len in
(len, sum, sum /. flen))
(0, 0., 0.)
[1.; 2.; 3.];;
val len : int = 3
val sum : float = 6.
val avg : float = 2.
I'm trying to make a function working out (and then outputting as a String) the difference between two elements in a list - 1st and 2nd, then 2nd and 3rd, and so on - I think I'm giving it a good go, but I currently keep running into error whack-a-mole, I've put the current error below, but first, obligatory code dump:
type Name = String
type Coordinates = (Int, Int)
type Pop = Int
type TotalPop = [Pop]
type City = (Name, (Coordinates, TotalPop))
testData :: [City]
testData = [("New York City", ((1,1), [5, 4, 3, 2])),
("Washingotn DC", ((3,3), [3, 2, 1, 1])),
("Los Angeles", ((2,2), [7, 7, 7, 5]))]
getPopGrowth :: [City] -> Name -> String
getPopGrowth cs name = concat
[getPercentages z ++ "\n" | (x,z) <- maybeToList (lookup name cs)] where
getPercentages z = unwords (map show z1) ++ "% " where
z1 = percentageIncrease z
percentageIncrease :: [Int] -> [Float]
percentageIncrease (x:xs)
| length (x:xs) > 2 = percentageIncrease (tail xs)
| otherwise = (a / b - 1) * 100.0 where
a = fromIntegral x :: Float
b = fromIntegral (head xs) :: Float
And the error I'm getting at the moment is:
error:
• Couldn't match expected type ‘[Float]’ with actual type ‘Float’
• In the expression: (a / b - 1) * 100.0
In an equation for ‘percentageIncrease’:
percentageIncrease (x : xs)
| length (x : xs) > 2 = percentageIncrease (tail xs)
| otherwise = (a / b - 1) * 100.0
where
a = fromIntegral x :: Float
b = fromIntegral (head xs) :: Float
|
92 | | otherwise = (a / b - 1) * 100.0 where
| ^^^^^^^^^^^^^^^^^^^
I would like to emphasise, I understand the error, but I do not know how to resolve it in such a way that I get the desired outcome of the function.
Just for some clarity around what I'm trying to do.
Input: getPopGrowth testData "New York City"
should Output: 25% 33.333% 50%
So far, you only calculate the percentage when the list has exactly two elements left. Less elements are not covered, and for longer lists, in all the steps before, the elements get dropped without further action. In the last step, however, you return a single Float instead of a list.
The following example creates an increase percentage in every step, concatenating it with the list resulting from applying the function to the tail of the list. Also, the base cases are all covered:
percentageIncrease :: [Int] -> [Float]
percentageIncrease [] = []
percentageIncrease (x:[]) = []
percentageIncrease (x:y:xs) = ((a / b - 1) * 100.0) : percentageIncrease (y:xs) where
a = fromIntegral x :: Float
b = fromIntegral y :: Float
Console output:
*Main> getPopGrowth testData "New York City"
"25.0 33.333336 50.0% \n"
I'm using the OCaml interface of the Apron library.
When I want to reduce the expression [| x + y -2 >= 0; x + y > - 3=0|], the result of tab is [|-3 + 1 * x + 1 * y >= 0|], How can I get the origin expression x + y - 3 >= 0?
let _ =
let vx = Var.of_string "x" in
let vy = Var.of_string "y" in
let env = Environment.make [||] [|vx;vy|] in
let c = Texpr1.cst env (Coeff.s_of_int 2) in
let c' = Texpr1.cst env (Coeff.s_of_int 3) in
let vx' = Texpr1.var env vx in
let vy' = Texpr1.var env vy in
let texpr = Texpr1.binop Add vx' vy' Real Near in
let texpr1 = Texpr1.binop Sub texpr c Real Near in
let texpr2 = Texpr1.binop Sub texpr c' Real Near in
(* let sum' = Texpr1.(Binop(Sub,x2,Cst c,Int,Near)) in *)
Format.printf "env = %a#." (fun x -> Environment.print x) env;
Format.printf "expr = %a#." (fun x -> Texpr1.print x) texpr;
let cons1 = Tcons1.make texpr1 Lincons0.SUPEQ in
let cons2 = Tcons1.make texpr2 Lincons0.SUPEQ in
let tab = Tcons1.array_make env 2 in
Tcons1.array_set tab 0 cons1;
Tcons1.array_set tab 1 cons2;
let abs = Abstract1.of_tcons_array manpk env tab in
let tab' = Abstract1.to_tcons_array manpk abs in
Format.printf "tab = %a#." (fun x -> Tcons1.array_print x) tab;
Format.printf "tab1 = %a#." (fun x -> Tcons1.array_print x) tab'
It seems to me that there is no inconsistency as the expressions -3 + 1 * x + 1 * y >= 0 and x + y - 3 >= 0 are semantically equivalent.
Why is the expression printed this way?
You are building a polyhedron (i'm guessing manpk refers to the polka manager) and even if it is built using tree-constraints, it is represented internally using linear-constraints. So when you convert it back to tree-constraints, you actually are converting a Lincons1.earray to a Tcons1.earray, hence the representation as a sum of monoms.
If by "get the origin expression" you mean, make Apron print it in a human friendly way, i suggest you convert your polyhedron to a linear-constraint array (using to_lincons_array) and then define your own pretty-printing utility over linear constraints.
Alternatively, you can use the Apronext library, which is a small wrapper I wrote around the Apron library which provides pp_print functions. On your specific example, using Linconsext.pp_print, you get: x+y>=3. Disclaimer, Apronext is neither efficient, nor reliable, nor maintained, so i suggest you dont use it extensively, but only for understanding purposes
I wrote the following code and put the error in the title.
Can someone help me please?
Error in line 7
punkteImKreis :: Double -> [(Double, Double)]
punkteImKreis k = [(x,y)|x <- [1.0,2.0..k-1.0],
y <- [1.0,2.0..k-1.0] ]
anteilImKreis :: Double -> Double
let l = length(punkteImKreis)
in anteilImKreis k = (fromIntegral (l)) / k^2
The error is in this definition:
anteilImKreis :: Double -> Double
let l = length(punkteImKreis)
in anteilImKreis k = (fromIntegral (l)) / k^2
let is an expression; therefore, it has to be inside a definition (that is, on the right of an = sign). This should be:
anteilImKreis :: Double -> Double
anteilImKreis k =
let l = length(punkteImKreis)
in (fromIntegral (l)) / k^2
By the way, you don't really need parentheses around an argument of a function when it's just one identifier. I would rewrite this as follows:
anteilImKreis :: Double -> Double
anteilImKreis k =
let l = length punkteImKreis
in (fromIntegral l) / k^2
Additionally, this exposes another error. punkteImKreis isn't a list; it's a function which returns a list, which means you can't directly take its length. I would assume you meant the following:
anteilImKreis :: Double -> Double
anteilImKreis k =
let l = length (punkteImKreis k)
in (fromIntegral l) / k^2
The idea is to walk over multiple dimensions, each one defined as a range
(* lower_bound, upper_bound, number_of_steps *)
type range = real * real * int
so functions like fun foo y x or fun foo z y x could be applied to the whole square XY or cube XY*Z.
SML/NJ doesn't like my implementation below :
test2.sml:7.5-22.6 Error: right-hand-side of clause doesn't agree with function result type [circularity]
expression: (real -> 'Z) -> unit
result type: 'Z -> 'Y
in declaration:
walk = (fn arg => (fn <pat> => <exp>))
Here's the code :
fun walk [] _ = ()
| walk (r::rs) f =
let
val (k0, k1, n) = r
val delta = k1 - k0
val step = delta / real n
fun loop 0 _ = ()
| loop i k =
let in
walk rs (f k) ; (* Note (f k) "eats" the first argument.
I guess SML doesn't like having the
type of walk change in the middle of its
definition *)
loop (i - 1) (k + step)
end
in
loop n k0
end
fun do2D y x = (* ... *) ()
fun do3D z y x = (* ... *) ()
val x_axis = (0.0, 1.0, 10)
val y_axis = (0.0, 1.0, 10)
val z_axis = (0.0, 1.0, 10)
val _ = walk [y_axis, x_axis] do2D
val _ = walk [z_axis, y_axis, x_axis] do3D
Is this kind of construct even possible ?
Any pointer welcomed.
Is walk expressible in ML's type system?
val walk : range list -> (real -> real -> unit) -> unit
val walk : range list -> (real -> real -> real -> unit) -> unit
The same one value cannot possibly exist with both those types in ML.
We can easily generate values for each of the desired types, though.
type range = real * real * int
signature WALK =
sig
type apply
val walk : range list -> apply -> unit
end
structure Walk0 : WALK =
struct
type apply = unit
fun walk _ _ = ()
end
functor WALKF (Walk : WALK) : WALK =
struct
type apply = real -> Walk.apply
fun walk ((low, high, steps)::rs) f =
let fun loop i =
if i > steps then () else
let val x = low + (high - low) * real i / real steps
in (Walk.walk rs (f x); loop (i + 1)) end
in loop 0 end
end
struture Walk1 = WALKF(Walk0)
struture Walk2 = WALKF(Walk1)
struture Walk3 = WALKF(Walk2)
With this, the following values exist with the desired types.
val Walk0.walk : range list -> unit -> unit
val Walk1.walk : range list -> (real -> unit) -> unit
val Walk2.walk : range list -> (real -> real -> unit) -> unit
val Walk3.walk : range list -> (real -> real -> real -> unit) -> unit
Then you only need to write
val _ = Walk2.walk [y_axis, x_axis] do2D
val _ = Walk3.walk [z_axis, y_axis, x_axis] do3D
To use the same walk for every dimensionality, you need it to use the same type for every dimensionality.
fun walk nil f = f nil
| walk ((low, high, steps)::rs) f =
let fun loop i =
if i > steps then () else
let val x = low + (high - low) * real i / real steps
in (walk rs (fn xs -> f (x::xs)); loop (i + 1)) end
in loop 0 end
Because the type is changed to
val walk : range list -> (real list -> unit) -> unit
your usage also has to change to
fun do2D [y,x] = (* ... *) ()
fun do3D [z,y,x] = (* ... *) ()
fun walk lst f = let
fun aux rev_prefix [] = f (rev rev_prefix)
| aux rev_prefix (r::rs) = let
val (k0, k1, n) = r
val delta = k1 - k0
val step = delta / real n
fun loop 0 _ = ()
| loop i k = (
aux (k+step :: rev_prefix) rs;
loop (i - 1) (k + step)
)
in
loop n k0
end
in
aux [] lst
end
fun do2D [x,y] = print (Real.toString x ^ "\t" ^
Real.toString y ^ "\n")
fun do3D [x,y,z] = print (Real.toString x ^ "\t" ^
Real.toString y ^ "\t" ^
Real.toString z ^ "\n")
val x_axis = (0.0, 1.0, 10)
val y_axis = (0.0, 1.0, 10)
val z_axis = (0.0, 1.0, 10)
val () = walk [y_axis, x_axis] do2D
val () = walk [z_axis, y_axis, x_axis] do3D
Found this implementation for variable number of arguments. Not sure it applies but it looks quite ugly.