Is there a way in OCaml for a variable inside a function to keep its value between function calls? It should work like Pythons default argument, which is a reference to the same object in every function call or the function should rather yield and not explicitly return a value. The effect should be the following (if the function was to return natural numbers):
foo ();;
0
foo ();;
1
Yes this is possible. You need to define a local ref outside of the closure and access its value and modify it every time the closure is used like so:
let foo =
(* local variable x *)
let x = ref 0 in
(* the closure that will be named foo *)
fun () -> let r = !x in
x := r+1; r
Related
how do I assign an expression with free type variables, like I assign other functions f as val x = f : ??
I have
fun curry f x y = f (x,y);
val dummy = fn (x,y) => {a=x,b=y} (* or anything with free type *)
val dummCd = fn x=> fn y=> {a=x,b=y}
I thought that 'curry dummy' would work like 'dummCd', but,
dummCd
val it = fn: 'a -> 'b -> {a: 'a, b: 'b}
and
curry dummy:
stdIn:13.1-13.8 Warning: type vars not generalized because of
value restriction are instantiated to dummy types (X1,X2,...)
val it = fn : ?.X1 -> ?.X2 -> {a:?.X1, b:?.X2}
So this becomes useless when assigned.
I can do this:
fun x a b =curry dummy a b ;
but this is a bit clumsy. When I put what I do here, into a function
val a = fn tr => (fn a=> fn b=> tr a b)
val x = a (curry dummy)
val x = fn : ?.X1 -> ?.X2 -> {a:?.X1, b:?.X2}
I get the same problem back.
How can I assign 'curry dummy' without using the extra a and b ? I mean like
val x = a ( curry dummy )
where a might be a function, and x behaves like dummCd
Thanks for tips
Sadly, you cannot do what you want.
In Standard ML '97, a value declaration can only bind a type variable if the right-hand side of the binding is a "non-expansive" expression, meaning that it conforms to a very restrictive subset of the expression syntax that doesn't make it possible to generate any new ref cells or exception names. Since this is a syntactic check, it doesn't take into account the definition of curry at all; you know that curry doesn't create any ref cells or exception names (and that val dummCd = curry dummy would therefore be safe), but all the compiler sees at this point is that curry dummy calls a function that could do those things.
So if you want dummCd to be called with arbitrary types (meaning, you want it to have the non-trivial type scheme ∀αβ.α→β→{a:α,b:β} with bound type variables), then you'll need to declare it using e.g. val dummCd = fn ... or fun dummCd ...; you can't just write val dummCd = ... with whatever you want on the right-hand side.
Standard ML '90 was a bit more permissive in this respect — it encoded the relevant information about the behavior of curry into the type system (by marking a type variable as "imperative", e.g. '_a rather than 'a, if it was involved in the types of any ref cells or exception names), and used that type information to decide whether val dummCd = curry dummy should be allowed to bind its type variables — but that system was deemed too messy and complicated, especially since it forced implementation details into signatures, so it was scrapped in Standard ML '97 and replaced with the current syntax-only system where all type variables are presumed imperative.
In studying OCaml I found this bit of code that I was sure would throw an exception, but instead it returned the value 1.
let x = 1 in
let f y = x in
let x = 2 in
f 0;;
If I think of it sequentially, ok, x takes the value one. Then in the lower context, we say f y = x. Since y isn't defined, I would think right here the compiler should throw an exception. Even if y were defined, I'd think this would perhaps "define f at y" if it acts kidn of like Haskell. But I would not expect it to define f for other values.
So I seem to be a little confused about how this is working.
Variables in OCaml don't change value, they are immutable. Your code defines two different things named x. The function f uses the first definition always. When you define a new value with the same name, this has no effect on f.
When you say let f y = x you are defining y, not referring to a previous y. You're giving the name y to the parameter of f, which can then be used in the definition of f (though your code chooses not to use y, which is perfectly fine).
I don't know why my code doesn't work.
fun lookup _ [] = 0
| lookup key ((k,v)::entries) =
if k = key
then v
else (lookup key entries)
That's what happened when I tested it in cmd.
val lookup = fn : ''a -> (''a * int) list -> int
- lookup (1,[(1,2),(2,3)]);
val it = fn : ((int * (int * int) list) * int) list -> int
There's nothing wrong with your code, you just didn't call lookup with enough arguments. You make a common mistakes among beginner SML programmers coming from other languages. I'll try to clarify that.
First, the most important thing to know about functions in Standard ML is this:
All functions in Standard ML take exactly one argument.
You might be confused at this point, because your lookup function looks as if it's taking two arguments. It kind of does, but not really.
There are two main "workarounds" (I'm using quotes because this is actually a great feature of the language) for representing functions that take multiple arguments:
1. Using curried functions
If you need to write a function which, conceptually, needs three arguments, then you'd write this:
fun quux a =
fn b =>
fn c =>
(* do something with a, b and c *)
So, quux is:
a function, which takes an argument a and returns
a function, which takes an argument b and returns
a function, which takes an argument c and returns
the result computed using a, b and c
How would you call quux? Like this, right?
((quux a) b) c
But function application is already left associative, so we can actually write this:
quux a b c
We don't need parentheses to "call" functions! In Standard ML parentheses don't mean "call this function". They're used just for grouping expressions together when you want to change associativity, like in mathematics: (1 + 2) * 3.
Because defining quux as above is really cumbersome, there's a syntactic shortcut in the language. Instead of writing this:
fun quux a =
fn b =>
fn c =>
(* do something with a, b and c *)
We can write just this:
fun quux a b c = (* do something with a, b and c *)
But, they're the same thing. quux is still a function which takes just argument a and returns a new function with argument b, which returns a new function which argument c.
Ok, so that was one way of representing multi-argument functions in Standard ML. It's also the one you used to define lookup.
2. Using tuples
Another common way of representing multi-argument functions is to accept a tuple (which may have from 2 to as many components as you wish). Here's the above example using a tuple now:
fun quux args =
case args of
(a,b,c) => (* do something with a, b and c *)
How could we call quux now? Like this:
quux (a,b,c)
Notice that I put a space between quux and the tuple. It's optional, but I do it all the time to keep remembering that function application in standard ML is not represented by parentheses. quux gets called because it's been put before the tuple (a,b,c). Tuples, however, do require parentheses, which is why you're seeing them above.
Again, as before, it's cumbersome to define quux like this:
fun quux args =
case args of
(a,b,c) => (* do something with a, b and c *)
So we can actually use another great feature of the language, pattern matching in argument position, that lets us write this:
fun quux (a,b,c) = (* do something with a, b and c *)
Ok, now we can really answer your question.
You defined lookup using the curried function syntax:
fun lookup _ [] = 0
But you "called" lookup using the tuple syntax, where 1 is the first element of the tuple and [(1,2),(2,3)] is the second element.
lookup (1, [(1,2),(2,3)])
Why doesn't the compiler complain, though. In this unfortunate case, it doesn't because it happens that the type of the first argument of lookup is a tuple. So, you've basically called lookup with a single argument.
What you wanted was this:
lookup 1 [(1,2),(2,3)]
Notice that I'm not defining a tuple anymore.
Is there any way to check/test the type of a variable?
I want to use it like this:
if x = int then foo
else if x = real then bar
else if x = string then ...
else .....
ML languages are statically typed, so it's not possible for something to have different types at different times. x can't sometimes have type int and at other times have the type string. If you need behavior like this, the normal way to go about it is to wrap the value in a container that encodes type information, like:
datatype wrapper = Int of int | Real of real | String of string
Then you can pattern-match on the constructor:
case x of Int x -> foo
| Real x -> bar
| String x -> ...
In this case, x is clearly typed as a wrapper, so that will work.
It's not possible to do what you want in general, even if x is of polymorphic type (without doing the wrapping yourself as Chuck suggests).
This is a deliberate design decision; it makes it possible to make very strong conclusions about functions, just based on their types, that you couldn't make otherwise. For instance, it lets you say that a function with type 'a -> 'a must be the identity function (or a function that always throws an exception, or a function that never returns). If you could inspect what 'a was at runtime, you could write a sneaky program like
fun sneaky (x : 'a) : 'a = if x = int then infinite_loop() else x
that would violate the rule. (This is a pretty trivial example, but there are lots of less-trivial things you can do by knowing your type system has this property.)
Basically, I want to have a function to return a polymorphic function, some thing like this:
fun foo () = fn x => x
So the foo function takes in a value of type unit and returns a polymorphic identity function
and the compiler is happy with that, it gives me:
val foo = fn : unit -> 'a -> 'a
but once I actually call the foo function, the return value is not what I expected
val it = fn : ?.X1 -> ?.X2
Can't generalize because of value restriction it says, any help? thanks in advance
For technical reasons, you are not allowed to generalize (i.e., make polymorphic) the results of a function call. The result of a call must have a monomorphic type. If this weren't the case, you could subvert the type system by the following dirty trick:
Call ref [] and get back a list of type forall 'a . 'a list ref
Insert a string.
Remove a function
and there you are: you are now executing the contents of an arbitrary string as code. Not Good.
By insisting that the value returned by ref [] be monomorphic, you ensure that it can be used as a list of strings or a list of functions but not both. So this is part of the price we pay for type safety.