Ad

Given the following numbers:

100 75 50 25 6 3

and the following operators:

(*) (-) (+) (/)

build an Expression, that yields 952 when it is evaluated (evaluate applies all the operators bottom - up)

Doubles are used for convenience, number is rounded and checked against an integer to mitigate floating point error that might accumulate.

module Example (solve, Expression(Value, Expr)) where

data Expression = Value Double | Expr Expression (Double -> Double -> Double) Expression

solve :: [Double] -> Expression
--solve = undefined


--- my brute-force solution
solve xs = head . filter validate . allExpressions os . allOrders $ xs
  where os = getPermutationsAtDepth (length xs - 1) ops

evaluate :: Expression -> Double
evaluate (Value x) = x
evaluate (Expr i o j) = (evaluate i) `o` (evaluate j)

validate :: Expression -> Bool
validate = (==952) . round . evaluate

-- ok because all the numbers are unique
removed :: Eq a => a -> [a] -> [a]
removed x = filter (/=x)

allOrders :: Eq a => [a] -> [[a]]
allOrders [x] = [[x]]
allOrders xs = concat [ [ x:ns | ns <- allOrders (removed x xs)] | x <- xs]


ops = [(*), (-), (+), (/)] :: [Op]
type Op = Double -> Double -> Double

data NodeTree a = Node a [NodeTree a] | Leaf a deriving (Show)

genTree :: a -> [a] -> Int -> NodeTree a
genTree root es 1     = Node root (map Leaf es)
genTree root es depth = Node root (map (\x -> genTree x es (depth-1)) es)

getPaths :: NodeTree a -> [[a]]
getPaths (Leaf x)    = [[x]]
getPaths (Node r xs) = concat [ [ r:t | t <- getPaths c] | c <- xs]

getPermutationsAtDepth :: Int -> [a] -> [[a]]
getPermutationsAtDepth 1     xs = [xs]
getPermutationsAtDepth depth xs = concat . map getPaths . map (\x -> genTree x xs d) $ xs where d = depth - 1

toExpression :: [Op] -> [Double] -> Expression
toExpression _  []             = error "should not be more operators than values!"
toExpression [] [e]            = Value e
toExpression (o:os) (e:es) = Expr (Value e) o (toExpression os es)

allExpressions :: [[Op]] -> [[Double]] -> [Expression]
allExpressions os es = [toExpression o e | o <- os, e <- es]

improve speed, check only up until n/2

Code
Diff
  • module Divisors where
    
    divisors :: Integer -> [Integer]
    divisors n = filter ((0 ==) . mod n) [1..n `div` 2] ++ [n]
    • module Divisors where
    • divisors :: Integer -> [Integer]
    • divisors n = filter ((0 ==) . mod n) [1..n]
    • divisors n = filter ((0 ==) . mod n) [1..n `div` 2] ++ [n]