Playing with Rust's tuples - tuples

Here's the link where was playing with Rust:
http://rustbyexample.com/match/guard.html
I found Rust showing warnings for the case when i negate an unsigned variable, so executing code below ends with
warning: negation of unsigned int variable may be unintentional
Code:
fn main() {
let some = 2953495866u;
let pair = (some, -some);
// TODO ^ Try different values for `pair`
println!("Tell me about {}", pair);
// Match can be used to destructure a tuple
match pair {
// Destructure the tuple
(x, y) if x == y => println!("These are twins"),
// The ^ `if condition` part is a guard
(x, y) if x + y == 0 => println!("Antimatter, kaboom!"),
// `_` means don't bind the value to a variable
(x, _) if x % 2 == 1 => println!("The first one is odd"),
_ => println!("No correlation..."),
}
}
But when you change the code into somewhat like
let pair = (2953495866u, -2953495866);
it runs silently ending up with tuple of (2953495866, 18446744070756055750) what is 2 unsigned integers. As for me, i'd rather expect warning here about casting negative number into uint.
What do you think about this situation?

An explanation, just in case. In this code:
fn main() {
//let some = 2953495866u;
let pair = (2953495866u, -2953495866);
// TODO ^ Try different values for `pair`
println!("Tell me about {}", pair);
// Match can be used to destructure a tuple
match pair {
// Destructure the tuple
(x, y) if x == y => println!("These are twins"),
// The ^ `if condition` part is a guard
(x, y) if x + y == 0 => println!("Antimatter, kaboom!"),
// `_` means don't bind the value to a variable
(x, _) if x % 2 == 1 => println!("The first one is odd"),
_ => println!("No correlation..."),
}
}
-2953495866 literal is untyped; it means that the type checker can deduce its concrete type from its usage. It turns out that it is stored into a tuple and then this tuple is destructured and its two components are compared. Because the first component type is uint (because the corresponding literal has u suffix), the type checker decides that the second component type is also uint, hence that literal should be uint as well.
That the lint about negation of unsigned value is not fired does seem like a bug in the compiler. I've submitted it here.

Related

why is a definition like this not producing an error in OCaml?

let f (x :: []) = [1;2];;
I don't understand the structure of this function.
Normally a function is declared like this:
let <function name> <arguments> = <function definition> But here
we give the function f a constant as an argument, namely [x], and then do
nothing with this argument. Instead, we assign the constant [1;2] to the function f?
To illustrate why having patterns in a function definition is useful, here are few examples of exhaustive patterns in arguments. The first common case is tuple:
let f (x,y) = x + y
In the code above,(x,y) is a pattern that binds the first and second element of a couple to the x and y variable respectively.
There is an equivalent construction for records
type vec2 = {x: float; y:float}
let f { x; _ } { y; _ } {x=x'; y = y' } = x +. y +. x' + y'
In this case {x; _}, {y; _ }, { x=x'; y=y'} are both exhaustive patterns.
For ordinary variants, it is less frequent to have useful and exhaustive patterns, but this can happen:
let f (x::_, _ | [], x) = x
Here, in this case we are either extracting the first element of the list in the first element of the tuple if the list is not empty, or the second element of the tuple.
Those cases are more frequent when using GADTs or empty types that makes it possible to have some branches of an algebraic not inhabited for a specific subtype.
For instance, the pattern in
type empty = |
let f (None:empty option) = ()
is exhaustive because the only possible value of the type empty option is None.
utop # let f x :: [] = [1;2];;
Error: Syntax error
This does give me an error. The following will compile.
let f (x :: []) = [1; 2]
But produces a warning about incomplete pattern match, because a list can have zero or any number of elements. A list with one element is just one specific example.
utop # let f (x :: []) = [1; 2];;
Line 1, characters 6-24:
Warning 8 [partial-match]: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
_::_::_
val f : 'a list -> int list = <fun>
It's worth noting that [x] is not a constant in a function like this. It is binding the name x to the one element in the list, whatever that happens to be.
Consider:
utop # let foo [x] = x;;
Line 1, characters 8-15:
Warning 8 [partial-match]: this pattern-matching is not exhaustive.
Here is an example of a case that is not matched:
_::_::_
val foo : 'a list -> 'a = <fun>
utop # foo [42];;
- : int = 42
Of course, this is a silly function, since x is never used by the function. You might just have written the following, using _ to indicate a value that we don't care enough about to give a name to.
let foo [_] = [1; 2]

SML - error in finding elements in list

I'm new to SML. I've written a function which takes 2 int and a list of tuples as input.
fun move(x,y,mylist:(int * int)list): NOxNO =
let
val counter = ref y-1
in
if y=1 then (x,y)
else (
while !counter > 0 do (
if List.exists (fn s => s = (x,!counter)) mylist
then counter := !counter - 1
else break
);
if !counter = 0 then (x,y) else (x,y-1)
)
end
I may have syntax error since I'm a beginner. What the function is trying to do is: it will check the list to find all the tuples whose first element is x and second element varies from 1 to y-1 (tuples like this: (x,1) (x,2) ... (x,y-1) ) and if all of them exist in the list it will return (x,y) else (x,y-1). I used a while loop and a counter. counter is set to y-1 at first and in while loop if (x,counter) was found, counter's value will decrease. At last if counter=0 it means we have found all the tuples. After running the program I encountered this error:
Caught Error ../compiler/TopLevel/interact/evalloop.sml:296.17-296.20
../compiler/TopLevel/interact/evalloop.sml:44.55
../compiler/TopLevel/interact/evalloop.sml:66.19-66.27
What's wrong?
Here's some feedback:
(Error) As Andreas Rossberg said, break doesn't exist. But if you use (), the loop won't terminate when y > 1 and the predicate evaluates to false. You probably want to "break" by setting counter := 0 or counter := -1, depending on what you want the subsequent if !counter = 0 ... to do.
(Error) As Andreas Rossberg said, ref y-1 gives the following type error:
! Toplevel input:
! val r = ref y-1;
! ^
! Type clash: expression of type
! int
! cannot have type
! int ref
This is because function application (ref y) binds tighter than infix operators (y-1). What you mean is ref (y-1), since you can't subtract 1 from a reference.
This isn't very comprehensible or robust. I tried to run it in the simplest case I could think of,
val test1 = move (1,1,[])
But that's a weird base case not handled by the loop. If I change the numbers slightly,
val test2 = move (5,6,[])
then it returns either (5,6) or (5,5) depending on what you change break into.
Based on your description below the code, here is a suggested implementation, although I'm still not completely certain I understand the use of this function:
(* verticalPointsExist (x, y, ps) checks that
* (x,1), (x,2), ..., (x,y-1) are all in ps. *)
fun verticalPointsExist (_, 0, _) = true
| verticalPointsExist (x, y, ps) = List.exists (fn p => (x,y) = p) ps
andalso verticalPointsExist (x, y - 1, ps)
fun move (x, y, ps) =
if verticalPointsExist (x, y, ps) then (x,y) else (x,y-1)
Considerations I made:
Use recursion rather than iteration.
Split the checking part into a helper function, so move doesn't do two things.
Give the functions good names so the code reads more easily. Since I don't know the domain and am really guessing as to whether y is some kind of vertical dimension, there are probably even better names out there. (verticalLineExists? verticalPathClear?) Maybe a more general function will have a better name, e.g. one that took two points and saw that the line is clear between them.
There is no break in ML. You probably just want to write () there. Also, you'll need parens around the argument to ref in line 3.

Multiple input types with fold

I am trying to figure out how to implement the fold functions on inputs of differing types. As a sample, I'll use the count function for a list (though, I have multiple functions to implement for this).
Assuming an int list input (this should work with any type of list, though), my count function would be
val count = foldr (fn(x:int,y)=>y+1) 0 ;
val count = fn : int list -> int
However, I am attempting to make a count function where the type is
val count = fn : int list * bool list -> int
where the int list is the universe of the set, and the bool determines which values of the universe are in the set. ie, (1,3,5,6),(true,false,false,true) results in a final set of (1,6), which would have a count of 2. My first thought to try this was some form of
val count= foldr (fn(x:(int*bool),y)=>if #2x then y+1 else y ) 0 ;
but this results in a return type of
val count = fn : (int * bool) list -> int
which is not quite what I need. Logically, they are similar, but I am expected to group the two types together in one list each.
You could use ListPair.foldl:
fun count (xs, bs) = ListPair.foldl (fn (x, b, acc) => ...) ... (xs, bs)
where the first ... is some combination of x, b and acc and the second ... is the initial value.
This assumes that xs and bs are equally long, and in case they're not, discards the remaining elements in the longer list. (You should probably try to justify if this gives the correct answer in either case xs or bs is longer.)
Otherwise, you need to combine (aka zip) your int list × bool list into an (int × bool) list by making a function that combines two lists, and use this function in combination with the folding you are already doing.
fun combine (x::xs, y::ys) = ...
| combine (..., ...) = ...
This function could be equivalent to ListPair.zip.

finding the first occurence in a list

I want to find the first occurence of a digit in a list :
let pos_list = function (list , x) ->
let rec pos = function
|([] , x , i) -> i
|([y] , x , i) -> if y == x then i
|(s::t , x , i) -> if s == x then i else pos(t , x , i + 1) in pos(list , x , 0) ;;
but the compiler complain that the expression is a "uint" type , and was used instead with a "int" type .
Remove the second case from the pattern matching. This case is already matched by the last one with s = y, t = []. So the function can be simplified to
let pos_list (list, x) =
let rec pos = function
| ([], x, i) -> i
| (s::t, x, i) -> if s == x then i else pos(t, x, i + 1) in pos(list, x, 0) ;;
Why are you using == (physical equality) instead = which is structural equality? I realize that this might not make a difference if you only have integers but it might yield unexpected behaviour down the road.
See the Comparisons section in the doc: http://caml.inria.fr/pub/docs/manual-ocaml/libref/Pervasives.html
Pavel Zaichenkov's answer is of course the best one, but you might be interested in knowing the exact cause of the error. Namely, when you have
if y == x then i
without a corresponding else expression, the whole expression is treated as
if y == x then i else ()
where () is the only value of the type unit (and not uint), which is the type of expressions that are evaluated for their side effects only. Since both branches of the if must have the same type, i is deemed to have type unit also. Then, when type-checking the third branch of the pattern-matching, you try to add i and 1, which means that i should have type int, hence the type error.

SML: get index of item in list

I'm new to SML and I'm attempting to get the index of an item in a list. I know that using List.nth will give me the value of an item at a index position, but I want the index value. There may even be a built in function that I'm not aware of. In my case, the list will not contain duplicates so if the item is in the list I get the index, if not it returns ~1. Here is the code I have so far. It works, but I don't think it is very clean:
val L=[1,2,3,4,5];
val m=length L-1;
fun Index(item, m, L)=if m<0 then ~1 else
if List.nth(L, m)=item then m else Index(item,m-1,L);
To elaborate on my previous comment, I suggest some changes for an implementation that fits better in the ML idiom:
fun index(item, xs) =
let
fun index'(m, nil) = NONE
| index'(m, x::xr) = if x = item then SOME m else index'(m + 1, xr)
in
index'(0, xs)
end
The individual changes are:
Have index return a value of type int option. NONE means the item is not in the list, SOME i means it is in the list, and the index of its first occurrence is i. This way, no special values (~1) need be used and the function's intended usage can be inferred from its type.
Hide the parameter m by renaming the function to index' and wrapping it into an outer function index that calls it with the appropriate arguments. The prime character (`) often indicates auxiliary values.
Use pattern matching on the list to get to the individual elements, eliminating the need for List.nth.
Also note that most commonly, function and variable names begin with a lowercase letter (index rather than Index), while capital letters are used for constructor constants (SOME) and the like.
I would like to propose a simpler and less efficient version of this index function. I agree that it is not as desirable to use exceptions rather than int option, and that it is not tail-recursive. But it is certainly easier to read and thus may serve as learning material:
fun index (x, []) = raise Subscript
| index (x, y::ys) =
if x = y then 0 else 1 + index (x, ys)
fun index(list,n)=
= if n=0 then hd(list) else index(tl(list),n-1);
val index = fn : 'a list * int -> 'a
index([1,2,3,4,5],2);
val it = 3 : int
index([1,2,3,4,5],0);
val it = 1 : int