In other languages, we can have a function which takes no arguments. Can we have 0 argument function in ocaml?
Functions in OCaml have exactly one argument (ignoring complications due to optional arguments). So, you can't have a function with no arguments.
As #alfa64 says, you could consider a simple value as a function with no arguments. But it will always have the same value (which, in fact, makes it similar to a pure function).
If you want to write a function that doesn't actually require any arguments (one that has side effects, presumably), it is traditional to use () as its argument:
# let p () = Printf.printf "hello, world\n";;
val p : unit -> unit = <fun>
# p ();;
hello, world
- : unit = ()
#
In OCaml functions always have an arguments. Therefore, we might wonder how to translate the following say_hello C function in OCaml:
void
say_hello()
{
printf("Hello, world!\n");
}
There is a special type unit in OCaml which has only one value, written as (). While it might look odd and useless, it adds regularity to the language: a function not needing a specific argument can just take an argument of type unit, a function not returning a useful value usually returns a value of type unit. Here is how to translate the above say_hello function to OCaml:
# let say_hello () = print_endline "Hello, world!";;
val say_hello : unit -> unit = <fun>
Incidentally, template based meta-programming would be much easier in C++ if there were no type void but a similar unit type instead. It is quite common to treat separately functions having no arguments in template specialisations.
Object methods, while being similar to functions, do not require an argument.
# class example =
object
method a =
print_endline "This demonstrates a call to method a of class example"
end;;
class example : object method a : unit end
# let x = new example;;
val x : example = <obj>
# x # a ;;
This demonstrates a call to method a of class example
- : unit = ()
Instead of
let foo n = 55
You just
let foo = 55
And then call foo wherever.
Related
I have inherited some old code where each function is defined as an individual file. I am attempting to write a simple program to test this. I have written test.f a program that at its base calls the function in func.f and then reports the result.
Using ifort -c func.f I created the object file for func.f and then attempted to compile using ifort test.f func.o -o test. This gives me the error that func is not defined as a function or array. Any thoughts?
test.f is
PROGRAM test
REAL :: X,Y
REAL :: FUNC
X = 1.0
Y = func(X)
WRITE(6,*) X
END
and func.f is
FUNCTION func(X)
func = X
RETURN
END
A type declaration statement like
real func
declares that there exists an entity with name func. This may be either:
a function with real result; or
a variable of type real
In isolation, from just this declaration, it is not possible to determine which type of entity func is.
If func is not declared an array and there is no other use of func in the scope which is inconsistent with it being a function, then func is taken to be a function by any reference where it can be a function, such as
real func
print *, func(1)
end
In the absence of an array declaration for func, any use of func in the scope which is inconsistent with func a function will be an error. ifort will generally issue an error message in such case looking like
error #6410: This name has not been declared as an array or a function.
What uses of func in a scope would be inconsistent with func a function? Just about anything that doesn't look like f(...) in an expression. For example:
giving func some attribute a only variable may have
using it as a variable in an assignment statement1
providing explicit initialization
using its name when a reference is required
etc.
real :: func ! Function or variable?
save func ! Function can't be SAVEd
func = 1 ! Function name can't be on the left-hand side
print *, func ! Function name can't be used in an expression
print *, func(1) ! Oops, func isn't a function.
end
(All of these uses are consistent with being an array, we just haven't declared it as such.)
Some type declaration statements make it obvious the entity must be a variable:
real :: not_func = 1.
real, allocatable :: definitely_variable
real :: definitely_array(5)
end
That's all to say: if you intend to use real func to declare an external function func with implicit interface and real result, but you get a warning about "not an array or function" when you try to reference it then you've got something somewhere which means func isn't a function and you haven't said it's an array.
It could be quite boring to check for all cases where func could be misused, so let's make our life easier:
real, external :: func
Although without the external attribute specification the EXTERNAL attribute is applied if func is a function, there's certainly no harm it using it. Indeed, it's good: this way we've told the compiler that func really is a function. Which means that any use of func inconsistent with being a function is an error, instead of the function reference.
Try the previous example with external added.
You can also be precise about func being an external function using an interface block (good practice) or a procedure declaration statement.
1 Although a function reference can be a variable, like in
func(1) = 12 ! func a function not an array
this is only the case when the function result is a pointer. A function with implicit interface cannot have a pointer result so this use is not consistent with func a function. We should also avoid confusion with the statement function
real :: func
func(i) = i+1
This is consistent with func a function, but it's not an external function defined elsewhere.
I've been reading through the list of OCaml warnings and am unsure what some of them mean (no examples are provided). Specifically, I'd like to understand:
Examples of code that trigger the following warnings (I think my interpretation of what each warning means is different from what it actually means because I am finding it difficult to produce cases that trigger the warnings that aren't outright language errors):
5. Partially applied function: expression whose result has function type and is ignored.
6. Label omitted in function application.
28. Wildcard pattern given as argument to a constant constructor.
59. Assignment to non-mutable value
What an "ancestor variable" and an "extension constructor" are:
36. Unused ancestor variable.
38. Unused extension constructor.
What these mean:
61. Unboxable type in primitive declaration
62. Type constraint on GADT type declaration
To complete the list:
A wild card pattern can be used as argument of an argument-less constructor
type t = A
let f x = match x with A _ -> 0
Warning 28: wildcard pattern given as argument to a constant constructor
This warning is raised when one names an inherited class without using it:
class c = object end
class d = object
inherit c as super
end
Warning 36: unused ancestor variable super.
An extension construction is a constructor added to an extensible sum type like exn
module M:sig end = struct
type exn += Unused
end
Warning 38: unused exception Unused
With recent versions of OCaml, it is possible to avoid boxing record with only one field or variant types with one constructor. This unboxing currently requires an annotation
type t = I of int [##unboxed]
However, the default representation may change in the future.
This change is transparent except for the FFI. Which means that external are paticularly brittle if they involve type without an annotation:
type t = I of int
external id: t -> t = "%identity"
Warning 61: This primitive declaration uses type t, which is unannotated and
unboxable. The representation of such types may change in future
versions. You should annotate the declaration of t with [##boxed]
or [##unboxed].
Type constraints does not apply on GADT arguments when defining a variant type. For instance, in
type 'a t =
| A: 'a -> float t
| B of 'a
constraint 'a = float
Warning 62: Type constraints do not apply to GADT cases of variant types.
The warning explains that B [] is an error, whereas A[] is fine.
This warning is an internal flambda warning, which warns that a value that flambda conjectured to be non-mutable was, in-fact, mutable. This warning should not be raised in normal circumstances.
Here's an example for warning 5:
# let f a b = a + b;;
val f : int -> int -> int = <fun>
# ignore (f 3);;
Warning 5: this function application is partial,
maybe some arguments are missing.
- : unit = ()
Warning 6 is disabled by default. If you enable it, it's easy to produce:
$ rlwrap ocaml -w +6
OCaml version 4.06.1
# let f ~a = a * 10;;
val f : a:int -> int = <fun>
# f 3;;
Warning 6: label a was omitted in the application of this function.
- : int = 30
The rest are beyond what I can figure out without looking at compiler sources. Maybe an expert or two will show up who can give examples for them.
I'm trying to define a function that should receive an iterator where each item is a reference to a trait object. For example:
use std::fmt::Display;
fn show_items<'a>(items: impl Iterator<Item = &'a Display>) {
items.for_each(|item| println!("{}", item));
}
When I try to call it on an iterator where each item is a reference to a type implementing Display:
let items: Vec<u32> = (1..10).into_iter().collect();
show_items(items.iter());
I get an error:
error[E0271]: type mismatch resolving `<std::slice::Iter<'_, u32> as std::iter::Iterator>::Item == &dyn std::fmt::Display`
--> src/lib.rs:9:5
|
9 | show_items(items.iter());
| ^^^^^^^^^^ expected u32, found trait std::fmt::Display
|
= note: expected type `&u32`
found type `&dyn std::fmt::Display`
note: required by `show_items`
--> src/lib.rs:3:1
|
3 | fn show_items<'a>(items: impl Iterator<Item = &'a Display>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Why is &u32 not considered as &dyn std::fmt::Display?
An explicit cast works fine:
show_items(items.iter().map(|item| item as &Display));
It also works fine for a single item:
fn show_item(item: &Display) {
println!("{:?}", item);
}
let item: u32 = 1;
show_item(&item);
The implicit conversion from a type T to dyn Trait for a Trait implemented by T is a so-called unsized coercion, a special kind of coercion. While Rust is somewhat reluctant with implicit type conversions, coercions do happen implicitly at coercion sites, but not in other places.
Function call arguments are coercion sites. This explains why your show_item() function works as desired.
All coercions can also be performed explicitly using the as operator. For this reason, the version using map() works fine.
Your definition of show_items(),
fn show_items<'a>(items: impl Iterator<Item = &'a Display>)
on the other hand is a completely different story. The impl syntax used here is a shorthand for
fn show_items<'a, I>(items: I)
where
I: Iterator<Item = &'a dyn Display>,
The function is generic over the iterator type, and the compiler verifies that the type that you actually pass in implements the trait bound Iterator<Item = &'a dyn Display>. The type std::slice::Iter<'_, u32> from you example code simply does not, hence the error. There is no coercion that converts an argument to a different type to make it implement some trait bound required by a generic function. It is also entirely unclear what type to convert std::slice::Iter<'_, u32> to to turn it into an iterator over &dyn Display.
Note that your version of the function definition is unnecessarily restrictive by requiring an iterator over trait objects. It would be far more natural and more performant to simply require that the iterator items implement Display instead:
fn show_items<I>(items: I)
where
I: IntoIterator,
I::Item: Display,
(I also changed Iterator to IntoIterator, since this is more general and more convenient.)
I have a basic question about types in signatures. If I have two ocaml files like:
istr.ml
type t = int
let get_string f v = f v
and fstr.ml
type t = float
let get_string f v = f v
and a signature
stri.mli
module type STR =
sig
type t
val get_string: (t -> string) -> t -> string
end
What is the type t in the above signature? Is it polymorphic?
it is an abstract type that hides the implementation and prevents the user to use it directly. see module system or RWO
But I am not sure that your current examples will work as your code examples does not seem to be in modules.
In a.ml a record type t is defined and is also defined transparently
in a.mli, i.e. in d interface so that the type definition is available
to all other files.
a.ml also has a function, func, which returns a list of t.
Now in another file, b.ml i m calling func, now obviously ocaml
compiler wud nt be able to infer d type of objects stored in d list,
for compiler its just a list. so in b.ml, i hav something like dis,
let tlist = A.func in
let vart = List.hd tlist in
printf "%s\n" vart.name (*name is a field in record t*)
Now here i get a compiler error sayin "Unbound record field label
name" which makes sense as compiler can't infer d type of vart.
my first question: how do I explicitly provide d type of vart as t
here?
i tried doing "let vart:A.t = " but got the
same error.
I also tried creating another function to fetch the first element of d
list and mentioning return type as A.t, but then i got the "Unbound
value A.t". I did this:
let firstt = function
[] -> 0
| x :: _ -> A.t x ;;
The problem is compiler is unable to recognize A.t (a type) in b.ml
but is able to recognize function A.func. If I remove A.t from the
b.ml, i don'get any compiler errors.
The compiler is able to recognize A.t to designate type t from file a.ml.
On the other hand, t x where t is a type and x a variable is not a valid expression. This is the source of your problem. The compiler looks for the name t in the variables exported by a.ml. Since it cannot find this name used for a variable, it reports an error.
Now for what you were trying to do:
type annotations are not hints to the compiler in OCaml. It has an algorithm to infer the (most general, with some exceptions I am not entering into) type and then it checks that your annotation is at least a particularization of the most general type. The type annotation you provide will never (again, with some possible exceptions that do not concern you) make it change its mind.
To access in file b.ml the field f of a record r of type A.t, type r.A.f.
let tlist = A.func in
let vart = List.hd tlist in
printf "%s\n" vart.name (*name is a field in record t*)
Here tlist is a function, I suppose it is of type 'a -> A.t list, but you are applying an List.hd on that function when you write let vart = List.hd tlist.
You should provide the argument for your function to get the list of A.t for example let tlist = A.func (your_argument-s-_here), I guess this is the source of your error, the compiler is able to infer types between modules.