I was wondering if it is possible to have compile-time check in OCaml to make sure arrays are the correct length. For my problem, I want to verify that two GPU 1-dim vectors are of the same length before doing piecewise vector subtraction.
let init_value = 1
let length = 10_000_000
let x = GpuVector.create length init_value and y = GpuVector.create 9 init_value in
let z = GpuVector.sub v1 v2
In this example I would like it to throw a compile error as x and y are not the same length. As I am a OCaml noob I would like to know how I can achieve this? I am guessing that I will have to use functors or camlp4 (which I have never used before)
You cannot define a type family in OCaml for arrays of length n where n can have arbitrary length. It is however possible to use other mechanisms to ensure that you only GpuVector.sub arrays of compatible lengths.
The easiest mechanism to implement is defining a special module for GpuVector of length 9, and you can generalise the 9 by using functors. Here is an example implementation of a module GpuVectorFixedLength:
module GpuVectorFixedLength =
struct
module type P =
sig
val length : int
end
module type S =
sig
type t
val length : int
val create : int -> t
val sub : t -> t -> t
end
module Make(Parameter:P): S =
struct
type t = GpuVector.t
let length = Parameter.length
let create x = GpuVector.create length x
let sub = GpuVector.sub
end
end
You can use this by saying for instance
module GpuVectorHuge = GpuVectorFixedLength.Make(struct let length = 10_000_000 end)
module GpuVectorTiny = GpuVectorFixedLength.Make(struct let length = 9 end)
let x = GpuVectorHuge.create 1
let y = GpuVectorTiny.create 1
The definition of z is then rejected by the compiler:
let z = GpuVector.sub x y
^
Error: This expression has type GpuVectorHuge.t
but an expression was expected of type int array
We therefore successfully reflected in the type system the property for two arrays of having the same length. You can take advantage of module inclusion to quickly implement a complete GpuVectorFixedLength.Make functor.
The slap library implements such kind of size static checks (for linear algebra).
The overall approach is described this abstract
Related
i need your help please, where is the error in my code ?
let create = Array.make_matrix 10 10;;
let assoc int = create int,create (char_of_int int);;
the error is
3 | let assoc int = create int,create (char_of_int int);;
^^^^^^^^^^^^^^^^^
Error: This expression has type char but an expression was expected of type
int
when you define a polymorphic function implicitly on Ocaml, it has a `weak type meaning that a type will be definitely assigned to the function after you've called it once, so because you called to create on an int, it now has a type int -> int array and won't accept a char as an argument.
This is the "value restriction". You can make it work by defining create like this:
let create v = Array.make_matrix 10 10 v
It works like this:
# let create v = Array.make_matrix 10 10 v;;
val create : 'a -> 'a array array = <fun>
# let assoc int = create int,create (char_of_int int);;
val assoc : int -> int array array * char array array = <fun>
The value restriction states that only "values" (in a certain sense) can be polymorphic; in particular, an expression that just applies a function can't be fully polymorphic. You define create by just applying a function to some values, so the value restriction prevents it from being polymorphic. The above definition defines create instead as a lambda (a fun in OCaml), which is a "value" per the value restriction. So it can be fully polymorphic.
You can read about the value restriction in Chapter 5 of the OCaml manual.
I would like to represent some scalar value (e.g. integers or strings)
by either it's real value or by some NA value and later store them
in a collection (e.g. a list). The purpose is to handle missing values.
To do this, I have implemented a signature
module type Scalar = sig
type t
type v = Value of t | NA
end
Now I have some polymorphic Vector type in mind that contains Scalars. Basically, some of the following
module Make_vector(S: Scalar) = struct
type t = S.v list
... rest of the functor ...
end
However, I cannot get this to work. I would like to do something like
module Int_vector = Make_vector(
struct
type t = int
end
)
module Str_vector = Make_vector(
struct
type t = string
end
)
... and so on for some types.
I have not yet worked a lot with OCaml so maybe this is not the right way. Any advises on how to realize such a polymorphic Scalar with a sum type?
The compiler always responds with the following message:
The parameter cannot be eliminated in the result type.
Please bind the argument to a module identifier.
Before, I have tried to implement Scalar as a sum type but ran into
complexity issues when realizing some features due to huge match clauses. Another (imo not so nice) option would be to use option. Is this a better strategy?
As far as I can see, you are structuring v as an input type to your functor, but you really want it to be an output type. Then when you apply the functor, you supply only the type t but not v. My suggestion is to move the definition of v into your implementation of Make_vector.
What are you trying to do exactly with modules / functors? Why simple 'a option list is not good enough? You can have functions operating on it, e.g.
let rec count_missing ?acc:(acc=0) = function
| None::tail -> count_missing ~acc:(acc+1) tail
| _::tail -> count_missing ~acc tail
| [] -> acc ;;
val count_missing : ?acc:int -> 'a option list -> int = <fun>
count_missing [None; Some 1; None; Some 2] ;;
- : int = 2
count_missing [Some "foo"; None; Some "bar"] ;;
- : int = 1
Given a list, I would like to produce a second list of elements selected from the first one.
For example:
let l1 = [1..4]
let n = [0; 2]
l1.[n]
should return 1 and 3, the first and third element of l1.
Unfortunately, it returns an error:
error FS0001: This expression was expected to have type
int but here has type int list
Now, I wonder, does exist a way to pass an argument n representing a list or, even better, an expression?
F# doesn't offer syntactical support for that sort of indexing. You can ask for a continuous slice of an array like below, but it doesn't cover your exact scenario.
let a = [|1 .. 4|]
let b = a.[0..2]
// returns [|1; 2; 3|]
You can easily write a function for that though:
let slice<'a> (indices: int list) (arr: 'a array) =
[| for idx in indices do yield arr.[idx] |]
slice [0; 2] a
// returns [| 1; 3 |]
I'm leaving proper handling of out-of-bounds access as an exercise ;)
With indexed properties, you should be able to define this for your types: just define a member Item with get(indexes) which accepts a list/array. But standard lists and arrays already have Item defined, and you can't have two at once...
I solved it this way:
List.map (fun index -> l1.[index]) n
It's inefficient for large lists, but works for me.
I am making a turtle graphics program by using ocaml. And this requires to provide an implementation of the module conforming to the following OCaml signature.
type program
type ins
val mf: float -> ins
val mb: float -> ins
val tl: float -> ins
val tr: float -> ins
val pu: ins
val pd: ins
val repeat: int -> program -> ins
val make_program: ins list -> program
type stroke
val strokes: program -> stroke list
type state
val animate: program -> state list
val strokes': program -> unit
val animate': program -> unit
Define a type for turtle programs and for turtle instructions.
The mf, mb, tl, tr, pu, pd, repeat and make_program functions are
used to build instructions and programs.
Define a type for strokes.
Program a function strokes that, given a turtle program, returns the
list of the strokes drawn by the turtle.
Define a type for the state of the turtle.
Program a function animate that, given a turtle program, returns the
list of states of the turtle.
The strokes' and animate' render the strokes and turtle animation
This is my code for mf, pu and pd:
type turtle = {
mutable x : float;
mutable y : float;
mutable phi : float;
mutable stt : int;
}
let round = int_of_float
let pi = 3.1415926535897932384626433832795
let rad_of_deg a = a *. pi /. 180.
let p = { x = 100.; y = 100.; phi = 0.; stt = 1 }
let pu() =
p.stt <- 0
let pd() =
p.stt <- 1
let mf l =
let x2 = (p.x) +. l *. cos (rad_of_deg p.phi)
and y2 = (p.y) +. l *. sin (rad_of_deg p.phi) in
moveto (round p.x) (round p.y);
if (p.stt == 1) then lineto (round x2) (round y2);
p.x <- x2;
p.y <- y2
The output of mf is:
val mf: float -> unit = <fun>
My question is how to make it look like the requirements?
I will try to give you a few hints, but you should consider to learn OCaml textbooks. I'm not going to teach you OCaml in a few keystrokes, not because I don't want to, but because it is impossible.
In OCaml a compilation unit consists of two parts:
module implementation
module signature
Module implementation consists of values and types, and each value has a type, associated with it. OCaml will infer types for values for you, but you can help it, using type annotations.
The implementation should be put in a file that has extension .ml. Signature should be put in a file with .mli extension. OCaml compiler will take them both, if they share the same name and build a compilation unit for you, that can be later linked into an executable.
For example you can put the given above signature into the file named gr.mli. Then you need to write a file that will implement this interface. You must name this file gr.ml and put your types and values into it. Then you can compile it using
ocamlbuild gr.cmo
and OCaml compiler will check whether your implementation actually implements the given signature. In order to conform to the signature, your module should contain all the values and types, specified in the signature and their types should be the same. Indeed, your implementation can contain more values, and types of values can be more general, than what is specified in a signature, but we're going to far away.
What you're showing in your example, (I'm refering to val mf: float -> unit = <fun>) is actually the output of the OCaml toplevel interpreter. And it consists of three parts (I use capital letter to denote that this is a variable part of the pattern):
val NAME : TYPE = VALUE
where NAME is a name of a value (in your case it is mf), TYPE is its inferred type (float -> unit in your case), and VALUE is a printable representation of the value. Since functions doesn't have a printable representation it is denoted as <fun> in your case. You can compare the type of your definition with the type of required definition (i.e., float -> ins). It isn't very hard to guess that this types can be equal if type ins is equal to type unit. Whether it is true depends on your implementation.
I hope, that this will help you. But this is not instead of reading textbooks. I'm just trying to give you starting hints.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am new in SML and it is my first time to learn a functional language. I suppose there is abstraction of SML. I have not found perfect explanation of how to achieve abstraction in SML. Does anyone can offer a explanation?
Generally speaking, there are at least two forms of "abstraction" in programming:
Abstracting the client (parameterisation)
Abstracting the implementation (encapsulation)
(If you care, these correspond to universal and existential quantification in logic and type theory.)
In ML, parameterisation can be done on two levels. Either in the small, using functions (abstraction over values) and polymorphism (abstraction over types). Note in particular that functions are first-class, so you can parameterise one function over another. For example:
fun map f [] = []
| map f (x::xs) = f x :: map f xs
abstracts list transformation over the transforming function f as well as the element types.
In the large, parameterisation can be done using the module system: a functor abstracts a whole module over another module (i.e., over both values and types). For example, you could also write the map function as a functor:
functor Mapper(type t; type u; val f : t -> u) =
struct
fun map [] = []
| map (x::xs) = f x :: map xs
end
But usually you use functors for mass abstraction, i.e., in cases where there is more than just a single function you need to parameterise.
Encapsulation is also achieved by using modules. Specifically, by sealing them, i.e., hiding details of their types behind a signature. For example, here is a (naive) implementation of integer sets:
signature INT_SET =
sig
type set
val empty : set
val add : int * set -> set
val mem : int * set -> bool
end
structure IntSet :> INT_SET = (* ':>' hides the implementation of type set *)
struct
type set = int list
val empty = []
fun add(x, s) = x::s
fun mem(x, s) = List.exists (fn y => y = x) s
end
Outside the structure IntSet, its type set is fully abstract, i.e., it cannot be interchanged with lists. That is the purpose of the so-called sealing operator :> for modules.
Both forms of abstraction can occur together. For example, in ML one would usually implement a set as a functor:
signature ORD =
sig
type t
val compare : t * t -> order
end
signature SET =
sig
type elem
type set
val empty : set
val add : elem * set -> set
val mem : elem * set -> bool
end
functor Set(Elem : ORD) :> SET where type elem = Elem.t =
struct
type elem = Elem.t
datatype set = Empty | Branch of set * elem * set
val empty = Empty
fun add(x, Empty) = Branch(Empty, x, Empty)
| add(x, Branch(l, y, r)) =
case Elem.compare(x, y) of
LESS => Branch(add(x, l), y, r)
| EQUAL => Branch(l, y, r)
| GREATER => Branch(l, y, add(x, r))
fun mem(x, Empty) = false
| mem(x, Branch(l, y, r)) =
case Elem.compare(x, y) of
LESS => mem(x, l)
| EQUAL => true
| GREATER => mem(x, r)
end
This implementation of sets works for any type for which an ordering function can be provided. Unlike the naive implementation before, it also uses a more efficient search tree as its implementation. However, that is not observable outside, because the type's implementation is again hidden.
SML programs frequently are build on a descriptive types for the problem at hand. The language then uses pattern matching to figure out what case your are working with.
datatype Shape = Circle of real | Rectangle of real*real | Square of real
val a = Circle(0.2)
val b = Square(1.3)
val c = Rectangle(4.0,2.0)
fun area (Circle(r)) = 3.14 * r * r
| area (Square(s)) = s * s
| area (Rectangle(b,h)) = b * h
Does this help to explain a little about sml?
In SML you can define "abstractions" by means of using a combination of things like algebraic data types and signatures.
Algebraic data types let you define new types specific to the problem domain and signatures let you provide functionality/behavior around those types and provide a convenient way to implement information hiding and extensibility and reusability.
Combining this things you can create "abstractions" whose implementation details are hidden from you and that you simply understand through their public interfaces (whatever the signature expose).