I have this bit of code:
fun foldr2(f, x::xs) =
if xs = [] then
x
else
f(x, foldr2(f, xs))
With the type signature
(''a * ''a -> ''a) * ''a list -> ''a
Looks pretty straight-forward, it takes a function that works over equality types and a list of equality type as arguments, because of the xs = [] comparison. However, for some reason it works on input such as (op +, [2.3, 2.7, 4.0]), when in SML/NJ reals are not an equality type. Can anyone help me shed some light on why this magic occurs?
I believe it's to do with the magical way in which + is overloaded for reals. To me, this almost verges on being a compiler bug, although I would have to look at the SML97 definition to see exactly what the correct behaviour is meant to be. The overloading over + is something of a nasty dark corner in SML, IMHO.
For example, if you define a function that is of type real * real -> real and pass that as an argument to foldr2 you get the type error you were expecting:
fun f (x : real * real) = 134.5
foldr2 (f, [1.4, 2.25, 7.0])
stdIn:8.1-8.29 Error: operator and operand don't agree [equality type required]
You can even induce the type error if you just add a type annotation to op +, which basically led me to the conclusion that it is the overloading of + that is causing the mysterious effect.
Related
I'm new to SML and don't quite understand my issue, although I'm certain I'm at fault. First off, here are two short functions I am testing and their descriptions.
MakeInterval - Takes a natural number r, (also used for rp) and a natural number t, and returns the interval [t-r,t+r].
fun MakeInterval(r,rp,t) =
if r + rp < 0 then []
else t-r :: MakeInterval(r-1,rp,t);
E.g. MakeInterval(3,3,10) will return [7,8,9,10,11,12,13]. If you have a suggestion for getting rid of rp, please let me know. It's the only way I could think of to keep track of the original value of r while maintaining sorted order.
NotDivisible - Takes a natural number r, a list of natural numbers ts1 and another list of natural numbers ts2. Code using ts2 isn't yet written.
r specifies the lower and upper bounds of the interval, (same as MakeInterval), and ts1 is a list of numbers to be fed into map with the MakeInterval function.
fun NotDivisible(r, ts1, ts2) =
map (fn x => MakeInterval(r,r,x), ts1);
This function should return a list of intervals. E.g. NotDivisible(3, [10,20,30],
[2,4,6]) will return (for now) [[7..13], [17..23], [27..33]].
After I get this working, I will begin manipulating these lists to find which numbers out of these intervals are indivisible by any of the numbers in ts2.
But for now, my issue lies with the function definitions as I have them. MakeInterval is defined with no issues and I have tested it on it's own. This is the error I receive when attempting to define NotDivisible:
stdIn:5.33-5.71 Error: operator and operand don't agree [tycon mismatch]
operator domain: 'Z -> 'Y
operand: (int -> int list) * 'X
in expression:
map ((fn x => MakeInterval <exp>),ts1)
I've tried specifying all types manually to no avail. Everything makes sense to me logically, but clearly there is a syntax issue here that I am not following.
The issue with the above is the invocation of map, the function is curried
map : ('a -> 'b) -> 'a list -> 'b list;
so, a small change to the parentheses:
fun NotDivisible(r, ts1, ts2) = map (fn x => MakeInterval(r,r,x)) ts1;
gives you:
val NotDivisible = fn : int * int list * 'a -> int list list
This function calculate count element y in list
fun func y xs=List.length(List.filter(fn x => x=y) xs);
val countElement = fn : ''a -> ''a ?.list -> int
func 1 [1,2,3,4];
val it = 1 : int
But, when I write func 1.1 [1.1,2.1,3.1,4.1]; I get error:
stdIn:64.1-64.35 Error: operator and operand don't agree [equality type required]
operator domain: ''Z
operand: real
in expression:
countElement 1.1
How can I solve it problem ?
real is not an equality type in SML 97. That means you cannot use = to compare two reals.
Standard ML has a concept of "equality types", or types that "admit equality"; or, more to the point, it has a concept of types that do not admit equality. You can only use = on types that do admit equality. (This is why its type is ''a * ''a -> bool rather than 'a * 'a -> bool. Type variables that start with '' can only be instantiated to equality types.)
In SML '97, real is one type that does not admit equality; so, the following code will not type-check:
val oneIsOne = (1.0 = 1.0) (* FAIL! *)
The reason for this design decision is that IEEE 754 (the standard that defines floating-point numbers) defines "equality" in a rather strange way — NaN is not equal to itself, and 0.0 is equal to ~0.0 even though 1 / 0.0 is not equal to 1 / ~0.0. The language designers decided that they didn't want = to differ from the semantics specified by IEEE 754, but that they also didn't want the semantics of = to be different for real than for all other types in the language. Instead, they completely eliminated = for real, and made the IEEE 754 definition semantics available as Real.== [link]. So, you can write:
fun countRealElement y xs = List.length (List.filter (fn x => Real.== (x,y)) xs)
val it = countRealElement 1.1 [1.1,2.1,3.1,4.1] (* 1 *)
(where countRealElement has type real -> real list -> int).
fun in_list (x : int, y : int list) =
if null y
then false
else if x=hd y then true
else in_list(x,tl y)
This is what my code currently looks like, it simply returns true if x appears in the the y list, false if not. The issue is I want it to be able to input "a" and ["a", "b", "c"] as well, or even have x be a list, and y be a list of lists. I am VERY new to ML (just started learning about it last week), and have searched for answers and cannot come up with anything.
If you change the first line to
fun in_list (x : ''a, y : ''a list) =
then it will behave as you want. Here ''a is an equality type variable that can stand for any type that supports the = operator.
You could also just leave out the types altogether and the most general correct type will be inferred.
Types can always be omitted in function declarations, with is only one exception: where overloading of operators could cause ambiguity. An example is
fun square x = x*x
because the type of x could be either int or real. (It will default to int, maybe not what you want.)
The point is that there is only one function hd. But the operator * can refer to two quite different functions.
fun a(list) =
let
val num = length(hd(list))
fun inner(list) =
if num = length(hd(list)) then
if tl(list) = nil then true
else inner(tl(list))
else false
in
if length(hd(list))-1 = length(tl(list)) then inner(tl(list))
else false
end;
this is ml code and I got this warning and type.
stdIn:6.16 Warning: calling polyEqual
val a = fn : ''a list list -> bool
I don't understand about the warning. why it appear and the type. ''a why it has two '? ''?
what is the difference between 'a list list and ''a list list?
Excerpted from ML Hints:
Warning: calling polyEqual [may occur] whenever you use = to
compare two values with polymorphic type.
For example, fun eq(x,y) = (x = y); will cause this warning to be
generated, because x and y will have polymorphic type ''a. This
is perfectly fine and you may ignore the warning. It is not reporting
any kind of semantic error or type error in your code. The compiler
reports the warning because there can be a slight ineffeciency in how
ML tests whether two values of a polymorphic type are equal. In
particular, to perform the equality test, the run-time system must
first determine what types of values you are currently using and then
determine whether the values are equal. The first part (checking the
run-time types) can make the = test slightly slower than if the
types are known ahead of time (such as when we test 3 = 4 and know
that the = test is being applied to integers). However, that is not
something most users of ML ever need to worry about...
To answer your second question,
why it has two '? ''? what is the difference between 'a list list and
''a list list?
''a is the same as 'a, but requires it to be an equality type. An equality type in SML is a type that can be compared using =. Non-equality types cannot be compared using =. When you create a datatype, you can specify whether it is an equality type or not.
dict=val a =[("a",[1,2]),("b",[2,3])] ;
here is the code which has implementation of look up in dictionary
fun look key [] = []
| look key ((a,b)::xs) = if (key =a ) then b else look key xs ;
which gives output as
test1.sml:8.36 Warning: calling polyEqual
It is because it does not know what are the types which are compared so
the below code says that both are string type .
fun look (key:string) [] = []
| look (key:string) ((a:string,b)::xs) = if (key =a ) then b else look (key:string) xs ;
I have a function sqrt which takes 2 floating point values, tolerance and number and gives out square root of the number within the specified tolerance. I use approximation method to do it.
let rec sqrt_rec approx tol number =
..................;;
let sqrt tol x = sqrt_rec (x/.2.0) tol x;;
I've another function map which takes a function and a list and applies the function to all elements of the list.
let rec map f l =
match l with
[] -> []
| h::t -> f h::map f t;;
Now I'm trying to create another function all_sqrt which basically takes 1 floating point value, 1 floating point list and maps function sqrt to all the elements.
let all_sqrt tol_value ip_list = List.map sqrt tol_value ip_list;;
It is obviously giving me error. I tried making tol_value also a list but it still throws up error.
Error: This function is applied to too many arguments;
maybe you forgot a `;'
I believe i'm doing mapping wrong.
The List module contains
val map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list
which is used like this:
let all_sqrt tol_value ip_list = List.map2 sqrt tol_value ip_list
This sounds like homework, since you say you are limited to certain functions in your solution. So I'll try to give just some suggestions, not an answer.
You want to use the same tolerance for all the values in your list. Imagine if there was a way to combine the tolerance with your sqrt function to produce a new function that takes just one parameter. You have something of the type float -> float -> float, and you somehow want to supply just the first float. This would give you back a function of type float -> float.
(As Wes pointed out, this works because your sqrt function is defined in Curried form.)
All I can say is that FP languages like OCaml (and Haskell) are exceptionally good at doing exactly this. In fact, it's kind of hard not to do it as long as you mind the precedences of various things. (I.e., think about the parentheses.)
I don't know O'Caml, but I do know Haskell, and it looks to me like you are applying map to 3 arguments "sqrt tol_value ip_list" map only takes two arguments, and is of the type ('a -> 'b) -> 'a list -> 'b list which means it accepts a function (functions only take one input and return one output), and a list, and returns a new list.
http://en.wikipedia.org/wiki/Currying