Newbie at SML
I have the following code that returns the absolute value of a list. I need it to be of type int list -> real list. Where do I place the statement that converts it to real while constraining this code to a single line?
val myabs = map(fn x => if x >= 0 then x else ~x) [1,~2, 3, ~4];
You convert an int to real using Real.fromInt:
- Real.fromInt 42;
> val it = 42.0 : real
You can convert an int list into a real list by List.map Real.fromInt:
- List.map Real.fromInt [1, 2, 3];
> val it = [1.0, 2.0, 3.0] : real list
You can convert an integer to its absolute using Int.abs:
- Int.abs ~42;
> val it = 42 : int
You can combine those two functions and so both convert an integer to its absolute and convert it to real:
- (Real.fromInt o Int.abs) ~42;
> val it = 42.0 : real
And you can do this for an entire list using List.map (Real.fromInt o Int.abs):
- List.map (Real.fromInt o Int.abs) [~1, ~2, ~3];
> val it = [1.0, 2.0, 3.0] : real list
You can express that as a single function:
fun myabs xs = List.map (fn x => Real.fromInt (Int.abs x)) xs
And you can shorten this function a bit:
val myabs = List.map (fn x => Real.fromInt (Int.abs x))
val myabs = List.map (fn x => (Real.fromInt o Int.abs) x)
val myabs = List.map (Real.fromInt o Int.abs)
So the only missing pieces were:
Instead of if x >= 0 then x else ~x, use Int.abs x.
To convert x to real, use Real.fromInt x.
To apply multiple functions in sequence, f (g x) or (f o g) x, like math.
Related
Hello every body im training some SMLs and im creating a code to get deviation of a int list . in the process of it , i need to get a Real list out of some numbers in a int list , which it doesnt let me get them. heres my code :
fun mean [] = 0.0
| mean (first::rest) =
let
fun sum [] = 0
| sum (x::xs) = x + sum xs
fun counter [] = 0
| counter (y::ys) = 1 + counter ys
in
Real.fromInt (sum (first::rest)) / Real.fromInt (counter (first::rest))
end;
fun deviation [] = 0.0
| deviation (first::rest) =
let
fun diff (x::xs) = (x - mean (x::xs)) :: diff xs;
in
diff (first , first::rest) + deviation rest
end;
the problem is here :
fun diff (x::xs) = (x - mean (x::xs) ) :: diff xs;
diff is a recursive function, but the base case is never defined. When you try to run diff on an empty list, you will get a pattern match error.
You also define diff to accept a list, but you call it with a tuple.
You define diff as returning a list, given that you are using ::, but then you use addition on the result of that function, which will not work.
Improving mean
You can simplify your sum and counter functions with folds.
fun mean [] = 0.0
| mean lst =
let
val sum = foldl op+ 0 lst
val counter = foldl (fn (_, c) => c + 1) 0 lst
in
Real.fromInt sum / Real.fromInt counter
end;
But this requires iterating the entire list twice, when both pieces of information can be ascertained at the same time.
fun sumLen(lst) =
foldl (fn (x, (sum, len)) => (sum+x, len+1)) (0, 0) lst
mean can now be implemented as:
fun mean(lst) =
let
val (sum, len) = sumLen(lst)
in
Real.fromInt sum / Real.fromInt len
end
Deviation
To get the differences from the mean for a list, you need only use map.
fun diffs(lst) =
let
val m = mean(lst)
in
map (fn x => Real.fromInt x - m) lst
end
Consider evaluating the following.
diffs [1, 2, 3, 4, 5, 6, 7, 8]
The result is:
[~3.5, ~2.5, ~1.5, ~0.5, 0.5, 1.5, 2.5, 3.5]
From there you can use map and Math.pow to square those differences, foldl to sum them, divide by the length of the list, and then Math.sqrt to get the standard deviation.
I am trying to write a simple add function that takes two real lists and adds the matching indices together and generates a real list, but for some reason I can't get it to accept real lists as the parameters, but instead only int lists.
fun add (nil, _) = nil
| add (_, nil) = nil
| add (a :: b, x :: y) = (a + x) :: add (b,y)
When I try running my test input, val addTest = add([1.0, 2.0, 3.0], [0.1, 0.2, 0.3]); it gives me:
Error: operator and operand do not agree [tycon mismatch]
operator domain: int list * int list
operand: real list * real list
And I am just curious as to why SML is defaulting to an int list even though the "+" operand is used for both reals and ints. Shouldn't it be accepting `a list instead of just int lists?
Yes, + (along with other arithmetic operators) is overloaded but not parametrically polymorphic.
So you can do 1.0 + 1.0 and 1 + 1 and they give a real and an int respectively.
But fun f x y = x + y can infer to either, so the compiler defaults to the int overload.
As an addition to your own answer, you can do with a single : real in your code:
fun add ([], _) = []
| add (_, []) = []
| add (x::xs, y::ys) = (x + y : real) :: add (xs, ys)
and it will infer that you must mean real in all the other places, too.
You could generalise this operation into one called zipWith:
- fun zipWith f [] _ = []
| zipWith f _ [] = []
| zipWith f (x::xs) (y::ys) = f (x, y) :: zipWith f xs ys
> val ('a, 'b, 'c) zipWith = fn :
('a * 'b -> 'c) -> 'a list -> 'b list -> 'c list
- val add = zipWith (op + : real * real -> real)
> val add = fn : real list -> real list -> real list
- add [1.0, 2.0, 3.0] [4.0, 5.0, 6.0];
> val it = [5.0, 7.0, 9.0] : real list
I found out that the default behavior for SML in a case like this is to default to int behavior, so if you have an operand that works for either reals or ints it will be evaluated as an int. As for the method above I was able to get my desired behavior by specifying the parameters in the tuple to be real lists like so:
fun add (nil, _) = nil
| add (_, nil) = nil
| add (a::b : real list, x::y : real list) = (a + x) :: add (b,y)
So what I have so far is something like this:
combs :: [[Char]]
combs = [[i] ++ [j] ++ [k] ++ [l] | i <- x, j <- x, k <- x, l <- x]
where x = "abc"
So this is the working function for n = 4, is there any way to make this work for an arbitrary number of generators? I could program in for n = 1, 2, 3 etc.. but ideally need it to work for any given n. For reference, x is just an arbitrary string of unique characters. I'm struggling to think of a way to somehow extract it to work for n generators.
You can use replicateM:
replicateM :: Applicative m => Int -> m a -> m [a]
E.g.:
generate :: Num a => Int -> [[a]]
generate = flip replicateM [1,2,3]
to generate all possiible lists of a given length and consisting of elements 1..3.
As far as I know, you can not construct list comprehension with an arbitrary number of generators, but usually if you do something with arbitrary depth, recursion is the way to do it.
So we have to think of solving this, in terms of itself. If you want all possible strings that can be generated with the characters in x. In case n = 0, we can generate exactly one string: the empty string.
combs 0 = [""]
so a list with one element [].
Now in case we want to generate strings with one characters, we can of course simply return x:
combs 1 = x
and now the question is what to do in case n > 1. In that case we can obtain all the strings with length n-1, and and for each such string, and each such character in x, produce a new string. Like:
combs n = [ (c:cs) | c <- x, cs <- combs (n-1) ]
Note that this makes the second case (n = 1) redundant. We can pick a character c from x, and prepend that to the empty string. So a basic implementation is:
combs :: Int -> [[Char]]
combs 0 = [""]
combs n = [(c:cs) | c <- x, cs <- combs (n-1)]
where x = "abc"
Now we can still look for improvements. List comprehensions are basically syntactical sugar for the list monad. So we can use liftA2 here:
import Control.Applicative(liftA2)
combs :: Int -> [[Char]]
combs 0 = [""]
combs n = liftA2 (:) x (combs (n-1))
where x = "abc"
we probably also want to make the set of characters a parameter:
import Control.Applicative(liftA2)
combs :: [Char] -> Int -> [[Char]]
combs _ 0 = [""]
combs x n = liftA2 (:) x (combs (n-1))
and we do not have to restrict us to characters, we can produce a certesian power for all possible types:
import Control.Applicative(liftA2)
combs :: [a] -> Int -> [[a]]
combs _ 0 = [[]]
combs x n = liftA2 (:) x (combs (n-1))
First I would translate the comprehension as a monadic expression.
x >>= \i -> x >>= \j -> x >>= \k -> x >>= \l -> return [i,j,k,l]
With n = 4 we see we have 4 x's, and generally will have n x's. Therefore, I am thinking about a list of x's of length n.
[x,x,x,x] :: [[a]]
How might we go from [x,x,x,x] to the monadic expression? A first good guess is foldr, since we want to do something with each element of the list. Particularly, we want to take an element from each x and form a list with these elements.
foldr :: (a -> b -> b) -> b -> [a] -> b
-- Or more accurately for our scenario:
foldr :: ([a] -> [[a]] -> [[a]]) -> [[a]] -> [[a]] -> [[a]]
There are two terms to come up with for foldr, which I will call f :: [a] -> [[a]] -> [[a]] and z :: [[a]]. We know what foldr f z [x,x,x,x] is:
foldr f z [x,x,x,x] = f x (f x (f x (f x z)))
If we add parentheses to the earlier monadic expression, we have this:
x >>= \i -> (x >>= \j -> (x >>= \k -> (x >>= \l -> return [i,j,k,l])))
You can see how the two expressions are looking similar. We should be able to find an f and z to make them the same. If we choose f = \x a -> x >>= \x' -> a >>= \a' -> return (x' : a') we get:
f x (f x (f x (f x z)))
= (\x a -> a >>= \a' -> x >>= \x' -> return (x' : a')) x (f x (f x (f x z)))
= f x (f x (f x z)) >>= \a' -> x >>= \x' -> return (x' : a')
= f x (f x (f x z)) >>= \a' -> x >>= \l -> return (l : a')
= (f x (f x z) >>= \a' -> x >>= \k -> return (k : a')) >>= \a' -> x >>= \l -> return (l : a')
= f x (f x z) >>= \a' -> x >>= \k -> x >>= \l -> return (l : k : a')
Note that I have reversed the order of i,j,k,l to l,k,j,i but in context of finding combinations, this should be irrelevant. We could try a' ++ [x'] instead if it was really of concern.
The last step is because (a >>= \b -> c) >>= \d -> e is the same as a >>= \b -> c >>= \d -> e (when accounting for variable hygiene) and return a >>= \b -> c is the same as (\b -> c) a.
If we keep unfolding this expression, eventually we will reach z >>= \a' -> … on the front. The only choice that makes sense here then is z = [[]]. This means that foldr f z [] = [[]] which may not be desirable (preferring [] instead). Instead, we might use foldr1 (for non-empty lists, and we might use Data.NonEmpty) or we might add a separate clause for empty lists to combs.
Looking at f = \x a -> x >>= \x' -> a >>= \a' -> return (x' : a') we might realise this helpful equivalence: a >>= \b -> return (c b) = c <$> a. Therefore, f = \x a -> x >>= \x' -> (x' :) <$> a. Then also, a >>= \b -> c (g b) = g <$> a >>= \b -> c and so f = (:) <$> x >>= \x' -> x' <$> a. Finally, a <*> b = a >>= \x -> x <$> b and so f = (:) <$> x <*> a.
The official implementation of sequenceA for lists is foldr (\x a -> (:) <$> x <*> a) (pure []), exactly what we came up with here too. This can be further shortened as foldr (liftA2 (:)) (pure []) but there is possibly some optimisation difference that made the implementors not choose this.
Last step is to merely come up with a list of n x's. This is just replicate replicate n x. There happens to be a function which does both replication and sequencing, called replicateM replicateM n x.
This code is in Haskell. How can i do the same thing in OCAML?
perfect n = [x | x<-[1..n], sum(f x) == x]
f x = [i | i<-[1..x-1], x `mod` i ==0]
While Jeffrey's answer is correct, using appropriate libraries (in this case, sequence), you can get something that is similar in terseness and semantics to the Haskell style:
module S = Sequence
let sum = S.fold (+) 0
let f x = S.filter (fun i -> x mod i = 0) S.(1 -- (x-1))
let perfect n = S.filter (fun x -> sum (f x) = x) S.(1 -- n)
You're using many (really nice) features of Haskell that don't exist in OCaml.
For list comprehensions, you can use List.filter.
For the notation [x .. y] you can use this range function:
let range a b =
let rec go accum i =
if i > b then List.rev accum else go (i :: accum) (i + 1)
in
go [] a
For sum you can use this:
let sum = List.fold_left (+) 0
The idea is to walk over multiple dimensions, each one defined as a range
(* lower_bound, upper_bound, number_of_steps *)
type range = real * real * int
so functions like fun foo y x or fun foo z y x could be applied to the whole square XY or cube XY*Z.
SML/NJ doesn't like my implementation below :
test2.sml:7.5-22.6 Error: right-hand-side of clause doesn't agree with function result type [circularity]
expression: (real -> 'Z) -> unit
result type: 'Z -> 'Y
in declaration:
walk = (fn arg => (fn <pat> => <exp>))
Here's the code :
fun walk [] _ = ()
| walk (r::rs) f =
let
val (k0, k1, n) = r
val delta = k1 - k0
val step = delta / real n
fun loop 0 _ = ()
| loop i k =
let in
walk rs (f k) ; (* Note (f k) "eats" the first argument.
I guess SML doesn't like having the
type of walk change in the middle of its
definition *)
loop (i - 1) (k + step)
end
in
loop n k0
end
fun do2D y x = (* ... *) ()
fun do3D z y x = (* ... *) ()
val x_axis = (0.0, 1.0, 10)
val y_axis = (0.0, 1.0, 10)
val z_axis = (0.0, 1.0, 10)
val _ = walk [y_axis, x_axis] do2D
val _ = walk [z_axis, y_axis, x_axis] do3D
Is this kind of construct even possible ?
Any pointer welcomed.
Is walk expressible in ML's type system?
val walk : range list -> (real -> real -> unit) -> unit
val walk : range list -> (real -> real -> real -> unit) -> unit
The same one value cannot possibly exist with both those types in ML.
We can easily generate values for each of the desired types, though.
type range = real * real * int
signature WALK =
sig
type apply
val walk : range list -> apply -> unit
end
structure Walk0 : WALK =
struct
type apply = unit
fun walk _ _ = ()
end
functor WALKF (Walk : WALK) : WALK =
struct
type apply = real -> Walk.apply
fun walk ((low, high, steps)::rs) f =
let fun loop i =
if i > steps then () else
let val x = low + (high - low) * real i / real steps
in (Walk.walk rs (f x); loop (i + 1)) end
in loop 0 end
end
struture Walk1 = WALKF(Walk0)
struture Walk2 = WALKF(Walk1)
struture Walk3 = WALKF(Walk2)
With this, the following values exist with the desired types.
val Walk0.walk : range list -> unit -> unit
val Walk1.walk : range list -> (real -> unit) -> unit
val Walk2.walk : range list -> (real -> real -> unit) -> unit
val Walk3.walk : range list -> (real -> real -> real -> unit) -> unit
Then you only need to write
val _ = Walk2.walk [y_axis, x_axis] do2D
val _ = Walk3.walk [z_axis, y_axis, x_axis] do3D
To use the same walk for every dimensionality, you need it to use the same type for every dimensionality.
fun walk nil f = f nil
| walk ((low, high, steps)::rs) f =
let fun loop i =
if i > steps then () else
let val x = low + (high - low) * real i / real steps
in (walk rs (fn xs -> f (x::xs)); loop (i + 1)) end
in loop 0 end
Because the type is changed to
val walk : range list -> (real list -> unit) -> unit
your usage also has to change to
fun do2D [y,x] = (* ... *) ()
fun do3D [z,y,x] = (* ... *) ()
fun walk lst f = let
fun aux rev_prefix [] = f (rev rev_prefix)
| aux rev_prefix (r::rs) = let
val (k0, k1, n) = r
val delta = k1 - k0
val step = delta / real n
fun loop 0 _ = ()
| loop i k = (
aux (k+step :: rev_prefix) rs;
loop (i - 1) (k + step)
)
in
loop n k0
end
in
aux [] lst
end
fun do2D [x,y] = print (Real.toString x ^ "\t" ^
Real.toString y ^ "\n")
fun do3D [x,y,z] = print (Real.toString x ^ "\t" ^
Real.toString y ^ "\t" ^
Real.toString z ^ "\n")
val x_axis = (0.0, 1.0, 10)
val y_axis = (0.0, 1.0, 10)
val z_axis = (0.0, 1.0, 10)
val () = walk [y_axis, x_axis] do2D
val () = walk [z_axis, y_axis, x_axis] do3D
Found this implementation for variable number of arguments. Not sure it applies but it looks quite ugly.