Count down game in OCaml - algorithm

This is a quite typical game.
You are given a list of integers, together with a value.
You use parenthesis, +, -, *, / to get to closest to the given value.
It is not necessary that all integers inside the list must be used. And you are chasing for the closest value, if an identical one cannot be computed out.
For example, You are give [1;3;7;10;25;50] and 831. The closest you can do is
7 + (1 + 10) * (25 + 50) = 832
How to write a program to solve this in FP or ocaml?
How to apply the parenthesis?
How to generate all possible expressions?

let (|->) l f = List.concat (List.map f l)
type op = Add | Sub | Mul | Div
let apply op x y =
match op with
| Add -> x + y
| Sub -> x - y
| Mul -> x * y
| Div -> x / y
let valid op x y =
match op with
| Add -> true
| Sub -> x > y
| Mul -> true
| Div -> x mod y = 0
type expr = Val of int | App of op * expr * expr
let rec eval = function
| Val n -> if n > 0 then Some n else None
| App (o,l,r) ->
eval l |> map_option (fun x ->
eval r |> map_option (fun y ->
if valid o x y then Some (apply o x y)
else None))
let list_diff a b = List.filter (fun e -> not (List.mem e b)) a
let is_unique xs =
let rec aux = function
| [] -> true
| x :: xs when List.mem x xs -> false
| x :: xs -> aux xs in
aux xs
let rec values = function
| Val n -> [n]
| App (_,l,r) -> values l # values r
let solution e ns n =
list_diff (values e) ns = [] && is_unique (values e) &&
eval e = Some n
(* Brute force solution. *)
let split l =
let rec aux lhs acc = function
| [] | [_] -> []
| [y; z] -> (List.rev (y::lhs), [z])::acc
| hd::rhs ->
let lhs = hd::lhs in
aux lhs ((List.rev lhs, rhs)::acc) rhs in
aux [] [] l
let combine l r =
List.map (fun o->App (o,l,r)) [Add; Sub; Mul; Div]
let rec exprs = function
| [] -> []
| [n] -> [Val n]
| ns ->
split ns |-> (fun (ls,rs) ->
exprs ls |-> (fun l ->
exprs rs |-> (fun r ->
combine l r)))
let rec choices = function _ -> failwith "choices: implement as homework"
let guard n =
List.filter (fun e -> eval e = Some n)
let solutions ns n =
choices ns |-> (fun ns' ->
exprs ns' |> guard n)
(* Alternative implementation *)
let guard p e =
if p e then [e] else []
let solutions ns n =
choices ns |-> (fun ns' ->
exprs ns' |->
guard (fun e -> eval e = Some n))
For explanation, see Functional Programming in OCaml.

Related

Reverse list order without increasing complexity

I wanted an alternative to filter that would, instead of discarding the false cases, keep them in a separate place. I came up with the below, but unfortunately it reverses the list.
Obviously I could append x to ys or zs instead of cons, but this would dramatically increase complexity.
Is there a way to keep it in order without increasing complexity?
splitBy :: (a -> Bool) -> [a] -> ([a],[a])
splitBy f xs = splitBy' f xs ([],[])
where
splitBy' :: (a -> Bool) -> [a] -> ([a],[a]) -> ([a],[a])
splitBy' _ [] result = result
splitBy' f (x:xs) (ys,zs) = if f x then splitBy' f xs (x:ys,zs)
else splitBy' f xs (ys,x:zs)
As others have said, the function is called partition, and it works something like this
partition :: (a -> Bool) -> [a] -> ([a], [a])
partition f = foldr (\x ~(yes,no) ->
if f x
then (x:yes,no)
else (yes,x:no))
([], [])
except that the real version adds an explicit xs parameter, perhaps to help fusion rules work properly. If that funky lazy pattern match makes you nervous, you can write it like this instead:
partition f = foldr (\x r ->
if f x
then (x:fst r,snd r)
else (fst r,x:snd r))
([], [])
If the foldr seems mysterious to you, you can do it like this:
partition f [] = ([], [])
partition f (x:xs)
| f x = (x:fst r, snd r)
| otherwise = (fst r, x:snd r)
where r = partition f xs

Translate Haskell code into Standard ML (combinations with repetition)

I am writing a code for the permutation with repetition for n elements drawn from choice of k values. So the cardinality of my resulting set should have k^n elements. In Haskell, it is fairly easy. For example, one can just write:
import Control.Monad (replicateM)
main = mapM_ print (replicateM 2 [1,2,3])
then you will get a list as:
[1,1] [1,2] [1,3] [2,1] [2,2] [2,3] [3,1] [3,2] [3,3]
But on Standard ML, I don't know how to do.
I tried this:
fun combs_with_rep (k,xxs) =
case (k, xxs) of (0,_) => [[]]
|(_, []) => []
|(k, x::xs) =>List.map (fn ys => x::ys) (combs_with_rep((k-1),xxs))# combs_with_rep(k,xs)
But the list is not complete and I don't know why....
Is there an analog coding as the one in Haskell that does the same thing? Or how should I fix my sml code?
Any help is appreciated!
Just transform the monadic code:
rep_comb n xs -- n times choose 1 elem from xs, repetition allowed
= replicateM n xs
= sequence $ replicate n xs
= foldr k (return []) $ replicate n xs
where
k m m' = do { x <- m; xs <- m'; return (x:xs) }
= case n of 0 -> [[]] ;
_ -> k xs (rep_comb (n-1) xs)
where
k m m' = m >>= (\x->
m' >>= (\xs -> return (x:xs) ))
= case n of 0 -> [[]] ;
_ -> xs >>= (\y->
rep_comb (n-1) xs >>= (\ys -> [y:ys]))
-- i.e.
= case n of 0 -> [[]] ;
_ -> [y:ys | y<- xs, ys<- rep_comb (n-1) xs]
= case n of 0 -> [[]] ;
_ -> concatMap (\y-> map (y:) (rep_comb (n-1) xs)) xs
-- or, in a different order
= case n of 0 -> [[]] ;
_ -> [y:ys | ys<- rep_comb (n-1) xs, y<- xs]
= case n of 0 -> [[]] ;
_ -> concatMap (\ys-> map (:ys) xs) (rep_comb (n-1) xs)
Now you can translate this to ML.

minimum difference between numbers

We have K different sets of numbers. We have to choose a number from each set, so that the difference between the higher and the lower number is the minimum.
Any ideas?
Something like this (written in Haskell)?
import Data.List (minimum, maximum, minimumBy)
minDiff (x:xs) = comb (head x) (diff $ matches (head x)) x where
lenxs = length xs
diff m = maximum m - minimum m
matches y = minimumBy (\a b -> compare (diff a) (diff b)) $ p [] 0 where
md = map (minimumBy (\a b -> compare (abs (a - y)) (abs (b - y)))) xs
mds = [m | m <- foldl (\b a -> filter (\z -> abs (z - y) == abs (y - md!!a)) (xs!!a) : b) [] [0..lenxs - 1]]
p result index
| index == lenxs = [y:result]
| otherwise = do
p' <- mds!!index
p (p':result) (index + 1)
comb result difference [] = matches result
comb result difference (z:zs) =
let diff' = diff (matches z)
in if diff' < difference
then comb z diff' zs
else comb result difference zs
OUTPUT:
*Main> minDiff [[1,3,5,9,10],[2,4,6,8],[7,11,12,13]]
[5,6,7]

Simplifying selectionsort and mergesort

I have managed to implement insertionsort and quicksort in a couple of lines, but selectionsort and mergesort still give me headaches ;)
selectionsort [] = []
selectionsort (x:xs) =
let (minimum, greater) = extractMinimum x [] xs
in minimum : selectionsort greater
extractMinimum minimumSoFar greater [] = (minimumSoFar, greater)
extractMinimum minimumSoFar greater (x:xs)
| x < minimumSoFar = extractMinimum x (minimumSoFar:greater) xs
| otherwise = extractMinimum minimumSoFar (x:greater) xs
Is something like the extractMinimum function available in the standard library? I tried hoogling for (a -> a -> Bool/Ordering) -> [a] -> (a, [a]) without any luck.
mergesort [ ] = [ ]
mergesort [x] = [x]
mergesort xs =
let (left, right) = splitAt (length xs `div` 2) xs
in merge (mergesort left) (mergesort right)
merge xs [] = xs
merge [] ys = ys
merge xxs#(x:xs) yys#(y:ys)
| x < y = x : merge xs yys
| otherwise = y : merge xxs ys
Again, do I have to write merge myself, or can I reuse existing components? Hoogle gave me no useful results for (a -> a -> Bool/Ordering) -> [a] -> [a] -> [a].
There's nothing in the standard libraries, but at least merge is provided by a package on hackage, although I'm not sure it's worth pulling in a dependency for such a simple function.
However,
merge xxs#(x:xs) yys#(y:ys)
| x < y = x : merge xs yys
| otherwise = y : merge xxs ys
produces a non-stable sort, to get a stable sort, the condition to place x should be x <= y.
For extractMinimum, I haven't found anything either, but I can offer an alternative definition,
extractMinimum :: Ord a => a -> [a] -> (a,[a])
extractMinimum x = foldl' select (x, [])
where
select (mini, greater) y
| y < mini = (y, mini:greater)
| otherwise = (mini, y:greater)
A nice definition of selectionSort would be
import Data.List -- for unfoldr
selectionSort :: Ord a => [a] -> [a]
selectionSort = unfoldr getMin
where
getMin [] = Nothing
getMin (x:xs) = Just $ extractMinimum x xs
My suggestion for selection sort:
import Data.List
selectionsort xs = unfoldr f xs where
f [] = Nothing
f xs = Just $ extractMinimum xs
extractMinimum (x:xs) = foldl' f (x,[]) xs where
f (minimum, greater) x | x < minimum = (x, minimum : greater)
| otherwise = (minimum, x : greater)

Statement for checking only once?Haskell

I have two lists of unequal length. When I add both of them I want the final list to have the length of the longest list.
addtwolists [0,0,221,2121] [0,0,0,99,323,99,32,2332,23,23]
>[0,0,221,2220,323,99,32,2332,23,23]
addtwolists [945,45,4,45,22,34,2] [0,34,2,34,2]
>[945,79,6,79,24,34,2]
zerolist :: Int -> [Integer]
zerolist x = take x (repeat 0)
addtwolists :: [Integer] -> [Integer] -> [Integer]
addtwolists x y = zipWith (+) (x ++ (zerolist ((length y)-(length x)))) (y ++ (zerolist ((length x)-(length y))))
This code is inefficient. So I tried:
addtwolist :: [Integer] -> [Integer] -> [Integer]
addtwolist x y = zipWith (+) (x ++ [head (zerolist ((length y)-(length x))) | (length y) > (length x)]) (y ++ [head (zerolist ((length x)-(length y))) | (length x) > (length y)])
Any other way to increase the efficiency?Could you only check once to see which list is bigger?
Your implementation is slow because it looks like you call the length function on each list multiple times on each step of zipWith. Haskell computes list length by walking the entire list and counting the number of elements it traverses.
The first speedy method that came to my mind was explicit recursion.
addLists :: [Integer] -> [Integer] -> [Integer]
addLists xs [] = xs
addLists [] ys = ys
addLists (x:xs) (y:ys) = x + y : addLists xs ys
I'm not aware of any standard Prelude functions that would fill your exact need, but if you wanted to generalize this to a higher order function, you could do worse than this. The two new values passed to the zip function are filler used in computing the remaining portion of the long list after the short list has been exhausted.
zipWithExtend :: (a -> b -> c) -> [a] -> [b] -> a -> b -> [c]
zipWithExtend f [] [] a' b' = []
zipWithExtend f (a:as) [] a' b' = f a b' : zipWithExtend f as [] a' b'
zipWithExtend f [] (b:bs) a' b' = f a' b : zipWithExtend f [] bs a' b'
zipWithExtend f (a:as) (b:bs) a' b' = f a b : zipWithExtend f as bs a' b'
Usage:
> let as = [0,0,221,2121]
> let bs = [0,0,0,99,323,99,32,2332,23,23]
> zipWithExtend (+) as bs 0 0
[0,0,221,2220,323,99,32,2332,23,23]
This can be done in a single iteration, which should be a significant improvement for long lists. It's probably simplest with explicit recursion:
addTwoLists xs [] = xs
addTwoLists [] ys = ys
addTwoLists (x:xs) (y:ys) = x+y:addTwoLists xs ys
Just because I can't help bikeshedding, you might enjoy this function:
Prelude Data.Monoid Data.List> :t map mconcat . transpose
map mconcat . transpose :: Monoid b => [[b]] -> [b]
For example:
> map (getSum . mconcat) . transpose $ [map Sum [0..5], map Sum [10,20..100]]
[10,21,32,43,54,65,70,80,90,100]
Two suggestions:
addtwolists xs ys =
let common = zipWith (+) xs ys
len = length common
in common ++ drop len xs ++ drop len ys
addtwolists xs ys | length xs < length ys = zipWith (+) (xs ++ repeat 0) ys
| otherwise = zipWith (+) xs (ys ++ repeat 0)

Resources