I'm just starting to learn OCaml, and I was confused by how the OCaml compiler determines the input type of arguments in certain situations where the argument could be multiple types. I'm assuming I would need to explicitly state the type in these instances? For example:
let sign x =
if x > 0 then 1
else if x < 0 then -1
else 0
let _ = print_int(sign 1.5)
Throws "Error: This expression has type float but an expression was expected of type int"
But don't the comparison operators work with floats as well? Why does the compiler assume that the argument should be an int instead of saying something like the argument type is ambiguous (unless I'm mistaken and the type actually is not ambiguous)?
The built-in comparison operators in OCaml have the following type signature:
'a -> 'a -> bool. Note that while the argument types are generic ('a), they are both the same. So, when you have a comparison like x < 0, the compiler sees that the type of the second argument is int and then infer that the type of x must be int as well. Changing your comparisons to use floats, e.g. x < 0. will make your code type-check, but then it would no longer work for int inputs.
Related
module type ORDER = sig
type t
val leq : t -> t -> bool
val equal : t -> t -> bool
end
module Int:ORDER with type t = int = struct
type t = int
let leq = (<=)
let equal = (=)
end
Can someone explain to me this line :
module Int:ORDER with type t = int = struct
this --> with type t = int
I've tried without it :
Int.equal 3 3
Line 1, characters 10-11:
Error: This expression has type int but an expression was expected of type
Int.t
I can see what "It does", but I'm unable to explain it in words what it is happening, thank you
The colon operator in a module expression isn't just a signature constraint, it's also an abstraction construct. M : S requires the module M to have the signature S, and tells the compiler to forget everything about typing of M except for what is specified in S. This is where abstraction is born.
Given the definition module Int: S = struct … end (which is syntactic sugar for module S = (struct … end : S)), all the compiler knows about the types of elements of Int is what is recorded in S. If S is ORDER, its type t is abstract, and therefore Int.t is an abstract type: the fac that Int.t is actually an alias for int is hidden. Hiding the real implementation of a type is exactly what abstract types are about.
The signature that is actually desired for Int is
sig
type t = int
val leq : t -> t -> bool
val equal : t -> t -> bool
end
This is almost exactly the signature called ORDER, but with the type t being an alias for int rather than abstract. The with type construct allows using the name ORDER to construct the module type expression above. Given the definition of ORDER, writing
module Int : ORDER with type t = int = struct … end
is equivalent to writing
module Int : sig
type t = int
val leq : t -> t -> bool
val equal : t -> t -> bool
end = struct … end
Since the type Int.t is transparently equal to int, it can be used interchangeably with int.
A ORDER signature is mostly useful to pass the type to functors like Set and Map that build data structures that rely on an ordering relation for their elements. The data structure only depends on the abstract properties of the order relation, but the code that uses the data structure can still be aware of the type of the elements (thanks to another with type constraint, this one equating the type of data structure elements with the type of the functor argument). See “functors and type abstraction” in the language introduction.
Let's consider a type t and two variables x,y of type t.
Will the call compare x y be valid for any type t? I couldn't find any counterexample.
The polymorphic compare function works by recursively exploring the structure of values, providing an ad-hoc total ordering on OCaml values, used to define structural equality tested by the polymorphic = operator.
It is, by design, not defined on functions and closures, as observed by #antron. The recursive nature of the definition implies that structural equality is not defined on values containing a function or a closure. This recursive nature also imply that the compare function is not defined on recursive values, as mentioned by a #antron as well.
Structural equality, and therefore the compare function and the comparison operators, is not aware of structure invariants and cannot be used to compare (mildly) advanced data structures such as Sets, Maps, HashTbls and so on. If comparison of these structures is desired, a specialised function has to be written, this is why Set and Map define such a function.
When defining your own structures, a good rule of thumb is to distinguish between
concrete types, which are defined only in terms of primitive types and other concrete types. Concrete types should not be used for structures whose processing expects some invariants, because it is easy to create arbitrary values of this type breaking these invariants. For these types, the polymorphic comparison function and operators are appropriate.
abstract types, whose concrete definition is hidden. For these types, it is best to provide specialised comparison function. The mixture library defines a compare mixin that can be used to derive comparison operators from the implementation of a specialised compare function. Its use is illustrated in the README.
It doesn't work for function types:
# compare (fun x -> x) (fun x -> x);;
Exception: Invalid_argument "equal: functional value".
Likewise, it won't (generally) work for other types whose values can contain functions:
# type t = A | B of (int -> int);;
type t = A | B of (int -> int)
# compare A A;;
- : int = 0
# compare (B (fun x -> x)) A;;
- : int = 1
# compare (B (fun x -> x)) (B (fun x -> x));;
Exception: Invalid_argument "equal: functional value".
It also doesn't (generally) work for recursive values:
# type t = {self : t};;
type t = { self : t; }
# let rec v = {self = v};;
val v : t = {self = <cycle>}
# let rec v' = {self = v'};;
val v' : t = {self = <cycle>}
# compare v v;;
- : int = 0
# compare v v';;
(* Does not terminate. *)
These cases are also listed in the documentation for compare in Pervasives.
I am attempting to multiply two int types in OCAML and I am not sure on what I might be doing wrong
let prime = Int64.of_string("0x100000002b2") in
let temp = ref prime in
hash := Int64.mul(!temp,prime);
I get the error
Error: This expression has type 'a * 'b
but an expression was expected of type int64
Any suggestions on how I can fix this ?
Update:
I got reference to this method from here
I am curious what this means
val mul : int64 -> int64 -> int64
Multiplication.
How do we know how many parameters this method takes ?
Function parameters in OCaml are (in the usual idiom) placed after the name of the function, with no parentheses and no comma.
# Int64.mul 8L 9L;;
- : int64 = 72L
Commas are used to create tuples, but Int64.mul doesn't accept a tuple. It accepts two separate arguments as above. (In FP parlance, it's a curried function.)
(It might be worth working through a short tutorial on OCaml. You seem to be assuming it's like traditional C family languages, but it's rather different.)
Update
The type x -> y is the type of a function that accepts a parameter of type x and returns a value of type y. The type x -> y -> z is the type of a (curried) function that takes two parameters of types x and y and returns a value of type z. (This is a somewhat simplified way of looking at things, but is close enough to get started with.)
So the function mul that you cite takes two parameters of type int64 and returns a value of type int64.
(I repeat my advice about an OCaml tutorial. It's really worth learning about the OCaml type system before getting too deep into coding.)
Assuming I have an int64 variable (or other integer size) representing a valid unicode code-point, and I want to convert it into a rune in Go, what do I do?
In C I would have used a type cast something like:
c = (char) i; // 7 bit ascii only
But in Go, a type assertion won't work:
c, err = rune.( i)
Suggestions?
You just want rune(i). Casting is done via type(x).
Type assertions are something different. You use a type assertion when you need to go from a less specific type (like interface{}) to a more specific one. Additionally, a cast is checked at compile time, where type assertions happen at runtime.
Here's how you use a type assertion:
var (
x interface{}
y int
z string
)
x = 3
// x is now essentially boxed. Its type is interface{}, but it contains an int.
// This is somewhat analogous to the Object type in other languages
// (though not exactly).
y = x.(int) // succeeds
z = x.(string) // compiles, but fails at runtime
In Go, you want to do a conversion.
Conversions
Conversions are expressions of the form T(x) where T is a type and
x is an expression that can be converted to type T.
Conversion = Type "(" Expression ")" .
A non-constant value x can be converted to type T in any of these
cases:
x is assignable to T.
x's type and T have identical underlying types.
x's type and T are unnamed pointer types and their pointer base types have identical underlying types.
x's type and T are both integer or floating point types.
x's type and T are both complex types.
x is an integer or has type []byte or []rune and T is a string type.
x is a string and T is []byte or []rune.
You want to convert x, of type int, int32, or int64, to T of type rune, an alias for type int32. x's type and T are both integer types.
Therefore, T(x) is allowed and is written rune(x), for your example, c = rune(i).
Why is the type of a plus ( + ) considered to be int -> int -> int as opposed to (int * int) -> int? To me, the second makes sense because it "accepts" a 2-tuple (the addends) and returns a single int (their sum).
Thank you!
You can make a language where (+) has the type (int * int) -> int. In fact, SML works exactly this way. It just affects the meaning of infix operators. However OCaml conventions strongly favor the use of curried functions (of the type a -> b -> c) rather than uncurried ones. One nice result is that you can partially apply them. For example ((+) 7) is a meaningful expression of type int -> int. I find this notation useful quite often.
This might seem a little unhelpful, but it's because the function takes two arguments.
When a function takes a tuple, it is in effect taking a single argument.
Because (+) is an inline function, taking a single argument would not be useful, as it would look like + (1,2) as opposed to 1 + 2.