OCaml: Why does this compile when the variable is not defined? - ocaml

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).

Related

Why my cast on user def type doesnt work?

type card = int
type game = { dimension : int; p1 : card list; }
let fn (_dimension : int) (p1 : card list) : bool =
(int)p1 = (int)_dimension * 2
I want to check that p1 is exactly twice the size of dimension.
Your code doesn't look very much like OCaml code, so it's difficult to know how to help :-)
There is no operation in OCaml to change the type of a value. That wouldn't make sense in a strongly typed language. There are some things you can do with types, but "casting" isn't one of them.
So, there is no valid expression that looks like (int) expr. As #glennsl points out, there is a function that returns the length of a list. If that's what you're trying to calculate, you can use List.length _dimension. The other occurrences of (int) you can just remove. They aren't valid OCaml.
Your definition of fn doesn't use the type game anywhere, so the definition of game is unnecessary. However it makes me worry that you're expecting the definition to have an effect.
If you leave out all the type ascriptions in your definition of fn the compiler will deduce the most general type for your function. This means you can call it with any list to check its length. That would be more idiomatic in OCaml. I.e., you don't need to specify that p1 is a list of cards. The function makes sense for any list.

Understand structured binding in C++17 by analogy

I'm trying to understand structured binding introduced in C++17. The explanation on cppreference is not obvious to me, but it looks like
cv-auto ref-operator [x, y, z] = ...
is roughly equivalent to (not to consider array case)
cv-auto ref-operator unique_name = ...
#define x unique_name.member_a
#define y unique_name.member_b
#define z unique_name.member_c
The key point here is that x y z are not independently defined variables, but just aliases of the return value members. And cv-auto ref-operator applies to the return value, not the aliases (the syntax may be misleading here). For instance, see the cppreference example
float x{};
char y{};
int z{};
std::tuple<float&,char&&,int> tpl(x,std::move(y),z);
const auto& [a,b,c] = tpl;
// a names a structured binding of type float& that refers to x
// b names a structured binding of type char&& that refers to y
// c names a structured binding of type const int that refers to the 3rd element of tpl
If a b c are independently defined variables, with const auto& applying to them, c cannot be of type const int.
From a practical point of view, what are the key points this analogy failed to catch?
It might be insightful to consider this from another perspective.
In C++ we already had variables, objects with a name int a = 5 and objects that aren't variables and do not have a name: *new int. Structured bindings are a way to have names for all parts of a variable, while the whole variable has no explicit name. So it's the combination [x,y,z] that together names an variable with three members.
Importantly, they together name an object, so the compiler actually has to layout the object. Independent variables can be placed independently on the stack. but with structured bindings the compiler cannot do so (except for the normal as-if rule)
So when we consider the combination [x y z] as the name of the variable, it's clear that auto const& [x y z] makes the combination a const& variable.
We then have to consider what exactly the individual names x, y and z mean. Your question summarizes them as
cv-auto ref-operator unique_name = ...
#define x unique_name.member_a
#define y unique_name.member_b
#define z unique_name.member_c
That's a bit tricky. Where does member_a come from? It appears that unique_name has a member_a. You already excluded the array case, which has [0]. Tuples have get<0>(tpl). There might very well be a member_a behind the get<0>, but the name member_a could be private. member_a could also be less const-qualified than get<0>.
But yes, for the most simple case, a simple struct without bitfields, there will indeed be a corresponding member_a.

What is wrong with my code in sml?

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.

use non-default overloaded operator in smlnj

smlnj will make overloaded operator, like op + to use int by default, now I want to it returns a function in real * real -> real, how can I do in inline way?
"inline way" means not something like binding a new val:
fun add(x:real,y:real) = x + y;
If my memory is correct there is some grammar allows sml it to just do something like "cast" op + to real, but I can't really find it anywhere..
There are various ways that you can get SML to type op+ as the real counterpart.
Depending on what ever code you have,
You can as suggested, type annotate the surrounding function, thus enforcing the parameters to op+ to be of type real.
Since you are nonfixing the addition function (presumably for use as a higher order function?), you could just as well pass along the addition function from the real module Real.+
Or you could annotate it like this: op+ : real * real -> real, which is really ugly and stupid, considering you can use Real.+ instead. But it is an option.
If the default instance of the operator is not the one you need for your value's type, you can use type annotation on the operands to enforce the desired typing.
For example, while
val f = fn a => a + a
will be typed int -> int, this value
val g = fn a:real => a + a
will be typed real -> real.
You could declare
open Real
in the scope where you define the function, but I strongly advise against that. Type-annotating the function is the best way. You don't have to annotate every parameter, btw, it's enough to do one, or in this case, even the return type:
fun add(x : real, y) = x + y
fun add(x, y) : real = x + y

SML How to check variable type?

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.)