I am trying to define a polymorphic function sum over the type T, where type T can be int, real or list of type T. The sum for the case of int and real should work as expected. For the case of list of T, it should return the sum of corresponding elements of two lists (the length of the lists should be same).
Examples:
sum (INT 2, INT 3) = INT 5
sum (REAL 2.3, REAL 3.4) = REAL 5.7
sum(L [2, 3, 4], L [3, 4, 5]) = L [5, 7, 9]
sum(L L([2, 3, 4], [2, 3, 4]), L ([3, 4, 5], [3, 4, 5]) = L ([5, 7, 9], [3, 4, 5])
The function which I wrote are as follows:
datatype T = INT of int | REAL of real | L of T list;
fun sum (x:T, x':T) = case (x, x') of
(INT n, INT n') => INT (n + n')
| (REAL n, REAL n') => REAL (n + n')
| (L (x :: xs), L (y :: ys)) => L ((sum (x, y)) :: (sum (L xs, L
ys))
| (_,_) => REAL (0.0);
But for the above function I was getting the error:
Constructor applied to the incorrect argument.
expects: _ * [??? list]
but got: _ * [???]
in: :: (sum (x, y), sum (L xs, L ys))
unhandled exception: Fail: compilation aborted: parseAndElaborate reported errors
Hence I changed my code by adding nil as below. As far as I perceived, the reason for the error was the fact that cons operator was trying to concatenate T (INT or REAL) to T (INT or REAL) in the end as (sum (x, y), sum (L xs, L ys)) will eventually get evaluated by recursive call to INT or REAL . Hence I changed my code by adding nil (empty list) in the end
fun sum (x:T, x':T) = case (x, x') of
(INT n, INT n') => INT (n + n')
| (REAL n, REAL n') => REAL (n + n')
| (L (x :: xs), L (y :: ys)) => L ((sum (x, y)) :: (sum (L xs,
L ys)) :: nil)
| (_,_) => REAL (0.0);
But for this case, it behaves correctly for INT and REAL but not for the polymorphic list.
It behaves correctly for INT and REAL (as they are simpler to implement). For the list part, I guess there is some problem with the cons operator and am not able to figure out the solution.
The test cases which I executed and their outputs are as follows:
sum (L([INT(1)]), L([INT(3)]));
val it = L [INT 4,L []] : T
sum (L([INT(1),INT(2)]), L([INT(3),INT(4)]));
val it = L [INT 4,L [INT #,L #]] : T
P.S: Please ignore the last case (,) => REAL (0.0) as I will handle the case of type mismatch later.
This seems like a good use-case for mutually recursive functions:
datatype T = INT of int | REAL of real | L of T list
fun sum (x, x') = case (x, x') of
(INT n, INT n') => INT (n + n')
| (REAL n, REAL n') => REAL (n + n')
| (L ns, L ns') => L (sumLists (ns, ns'))
| (_, _) => ? (* mismatching types *)
and sumLists (x::xs, y::ys) = sum (x, y) :: sumLists (xs, ys)
| sumLists ([], []) = []
| sumLists (_, _) = ? (* mismatching lengths *)
Having REAL 0.0 as the result of mismatching types seems like a problem.
For example, why should sum (INT 2, L [INT 3]) be REAL 0.0?
And why should sum (INT 2, REAL 3.0) be REAL 0.0?
Consider either adding an alternate to INT and REAL that has "no value" if that makes sense for your domain, or, probably better, consider changing the sum function to maybe return a sum, if it can meaningfully be computed on all levels of the tree, i.e. val sum : T * T -> T option. It comes down to error handling.
Write tests that describe the intended behavior of your corner cases. In particular, when it comes to summing values that don't have the same type, and summing lists of mismatching length.
Your examples would look like this as tests:
val test1 = sum (L [INT 1], L [INT 3]) = L [INT 4]
val test2 = sum (L [INT 1, INT 2], L [INT 3, INT 4]) = L [INT 4, INT 6]
Except T isn't an equality type because it contains a real, so you need to write your own equality operator that uses an epsilon test (nearlyEqual) when you encounter a real, for example:
fun eqT (INT x, INT y) = x = y
| eqT (REAL x, REAL y) = nearlyEqual(x, y, someEps)
| eqT (L (x::xs), L (y::ys)) = eqT (x, y) andalso eqT (L ys, L xs)
| eqT (L [], L []) = true
| eqT (_, _) = false
Some of your corner cases might look like
val case1 = sum (INT 2, REAL 3.0)
val case2 = sum (INT 2, L [])
val case3 = sum (INT 2, L [INT 3])
val case4 = sum (L [INT 1], L [INT 1, INT 2])
val case5 = sum (L [INT 1], L [INT 1, REAL 2.0])
val case6 = sum (L [], L [L []])
Related
I want to split a list into groups with n elements. For example:
n = 2
[1, 2, 3, 4, 5, 6] ->[[1, 2], [3, 4], [5,6]]
n = 3
[1, 2, 3, 4, 5, 6] -> [[1, 2, 3] [4, 5, 6]]
I tried to implement a function, which returns n if n is 0 or greater than the length of the list and the fitted list if n is less than the length of the list.
split :: Int -> [a] -> Either Int [[a]]
split n [a]
|n <= lenght [a] = Right n (take n [a]) : (split n (drop n [a]))
|n == 0 = Left n
|otherwise = Left n
However, I get a "variable not in scope" error. I've already tried around, but I'm stuck.
Did I make a mistake with the data types?
You have a typo with lenght vs. length, but if we change that there are still errors.
If we look at Right n (take n [a]) we can see that Right and Left only accept a single argument.
Your pattern split n [a] also only matches a list with a single element.
Let's break this down into smaller pieces. Creating a function that splits a list is straightforward.
split' n [] = []
split' n lst = take n lst : (split' n $ drop n lst)
Prelude> split' 3 [1,2,3,4,5,6]
[[1,2,3],[4,5,6]]
Now it's straightforward to make this local to split to incorporate the checks you specified and return the desired Either type.
split :: Int -> [a] -> Either Int [[a]]
split n [] = Left n
split n lst
| n == 0 || n > length lst = Left n
| otherwise = Right lst'
where
split' n [] = []
split' n lst = take n lst : (split' n $ drop n lst)
lst' = split' n lst
How do you find nth elements in the matrix at a given row and column position? For example, if you have
type Matrice a = [[a]]
example :: Matrice Int
example = [ [3, 5],
[2, 1],
[0, 4],
[6, 8] ]
Prelude > example 0 1
5
Prelude > example 2 0
0
Prelude > example 1 1
2
I know how to work out with only given list such as
nth :: Int -> [a] -> Maybe a
nth _ [] = Nothing
nth 1 (x : _) = Just x
nth n (_ : xs) = nth (n - 1) xs
But my question is, how do you access nth element in a matrix as in the given example
Just handle each list individually, and !! will work:
Prelude> example
[[3,5],[2,1],[0,4],[6,8]]
Prelude> :t example
example :: Matrice Int
Prelude> example !! 0 !! 1
5
But lists are probably not the right data structure for this, because indexing is O(n). Depending on your task, Data.Vector or Data.Array may be better suited. See also Haskell: Lists, Arrays, Vectors, Sequences.
!! can be used for accessing an element by index, but be careful, since it's raising an exception, if the index is too large.
example !! 2 !! 0
And you've already written a function for accessing nth element of a list, just apply it twice:
nth :: Int -> Int -> [[a]] -> Maybe a
nth k n matrix = nth' n =<< nth' k matrix
where
nth' _ [] = Nothing
nth' 0 (x: _) = Just x
nth' n (_ : xs) = nth' (n - 1) xs
Or using your created Matrice type:
nth :: Matrice a -> Int -> Int -> Maybe a
nth matrix k n = nth' n =<< nth' k matrix
where
nth' _ [] = Nothing
nth' 0 (x: _) = Just x
nth' n (_ : xs) = nth' (n - 1) xs
I am attempting to create a function in OCaml that gives the "k-average" of consecutive elements in a list. For example:
average 4 [1; 2; 3; 4; 5; 6] = [2; 3; 4]
since the average of 1, 2, 3, 4 is 2, of 2, 3, 4, 5 is 3, and of 3, 4, 5, 6 is 4.
I have created a function that averages the list, but with every 2 elements:
let rec average2 xs = match xs with
| [] -> []
| x :: [] -> [x]
| x :: x' :: xs -> if xs = [] then [(x + x') / 2] else [(x + x') / 2] #
(average2 (x'::xs))
How can I modify this to allow me to average k-elements?
What you should do is just verify that the list has the proper length and then two recursive functions will do it easily :
let average n l =
if List.length l < n then failwith "List is too small"
else
(* this function computes one k-average and returns the result *)
let rec aux2 acc i = function
| hd :: tl when i < n -> aux2 (acc + hd) (i + 1) tl
| _ -> acc / n
in
let rec aux acc l = match l with
(* the resulting list is reversed *)
| [] -> List.rev acc
| _ :: tl ->
(* Get the k-average of the k first elements of the list *)
let avgn = aux2 0 0 l in
(* if the rest of the list is too small, we reached the
end for sure, end *)
if List.length tl < n then List.rev (avgn :: acc)
(* recursive call on the rest of the list (without the head) *)
else aux (avgn :: acc) tl
in aux [] l
I have a function:
let rec multiply x ls =
match ls with
[] -> []
| h::tl -> (x * h) :: multiply x tl
multiply 2 [1;2;3] = [2;4;6]
I would like a function that calls multiply from n to 0. I keep having problems because of the base case:
let rec multiply_all x ls = if x > 0
then (multiply n ls) :: multiply_all (n-1) (ls) else ????
I am not sure what to put after the else. I tried to make it
if x > 1 then (multiply n ls) :: multiply_all (n-1) (ls) else multiply all 1.
but that doesn't work.
Putting 1 there certainly doesn't work since multiply_all must return a list. So you need a list (of lists of int) to put there. But which list should it be?
The short answer is that in such simple cases, the list you need is usually the empty list: [].
As a slightly longer answer, we can consider the case for multiply_all 0 in relation to the intended results of multiply_all 1, multiply_all 2, etc., and try to find a pattern that fits. We want multiply_all to behave like this:
# multiply_all 2 [1;2;3];;
- : int list list = [[2; 4; 6]; [1; 2; 3]]
# multiply_all 1 [1;2;3];;
- : int list list = [[1; 2; 3]]
So calling multiply_all with some number N as first argument should give us a list of length N. In particular, multiply_all with N = 0 should give a list of length 0. The list of length 0 is the empty list.
Here is your completed definition:
let rec multiply_all x ls =
if x > 0 then (multiply x ls) :: multiply_all (x-1) (ls) else []
Just an other solution :
let multiply_all n l =
let multiply n= List.map (( * ) n) in
let rec aux i acc =
if i > n then acc
else aux (i+1) (multiply i l :: acc)
in
aux 1 []
;;
Test :
# multiply_all 5 [1;2;3];;
- : int list list =
[[5; 10; 15]; [4; 8; 12]; [3; 6; 9]; [2; 4; 6]; [1; 2; 3]]
First of all, your multiply method is pretty inefficient since it isn't tail recursive. Furthermore, the standard library provides you with tools to make that kind of function easier to write:
let multiply n = List.map (( * ) n);;;
val multiply : int -> int list -> int list = <fun>
multiply 5 [1;2;3];;
- : int list = [5; 10; 15]
Note: Also, use partial application when it doesn't obfuscate your code.
As of multiply_all, I'm not sure how to achieve it without JaneStreet's Core (see this question). However, here is a possible implementation using Core:
open Core.Std;; (*Using Core*)
let multiply_all n l =
let multiples = List.init n ~f:(fun x -> n-x) in (*This doesn't exist in Pervasives*)
List.map multiples ~f:(fun m -> multiply l m);;
val multiply_all : int list -> int -> int list list = <fun>
multiply_all 5 [1;2;3];;
- : int list list = [[5; 10; 15]; [4; 8; 12]; [3; 6; 9]; [2; 4; 6]; [1; 2; 3]]
Hope it helps. I'll keep this answer updated with my findings about List.init.
I have a function that returns a list like this:
[ [1, 2, 3], [], [5], [5,6], []]
But I want to replace the empty lists with 0, so that it looks like this
[ [1, 2, 3], [0], [5], [5,6], [0]]
So far I have tried filter and map with little success. Can someone please point me in the right direction?
Here is the code in question:
knightPlace:: [Int] -> [[Int]]
knightPlace n = makeboard n
where
makeboard n = [x | i<-[0..(length n -1 )], x <- [checkPos i]]
-- checkPos add zero
checkPos i = [j+1 | j<-[0..(length n -1 )], queenFilter n i j]
-- filters all rows, cols and diags, also knights
queenFilter n i j = and [n!!(i) == 0 && n!!(k) /=(j+1) && (n!!(k)==0 || (abs(n!!(k)-(j+1))/=abs(i-k))) && (n!!(k)==0 ||not( ((abs(i-k)==2)&& (abs(n!!(k)-(j+1))==1)) ||((abs(i-k)==1)&& (abs(n!!(k)-(j+1))==2)))) | k<-[0..(length n - 1)] ]
Called like
knightPlace [0, 0, 6, 0, 0, 4, 0, 0]
Consider that if you have a function foo that can transform [] to [0] and return every other list untouched, map foo is the final function that you want.
Replace xs with ys in l,
replaceWith :: [a] -> [a] -> [[a]]
replaceWith xs ys l = map (\x -> if x == xs then ys else x) l
In the case here,
replaceWith [] [0] [[1, 2, 3],[],[5],[5,6],[]]
Change your function with
knightPlace n = map (\x -> if null x then [0] else x) $ makeboard n
Also consider using pointfree style
knightPlace = map (\x -> if null x then [0] else x) . makeboard