[Haskell-cafe] How to dynamic plan in Haskell?
Thomas DuBuisson
thomas.dubuisson at gmail.com
Sat May 18 15:37:36 UTC 2019
That prior mail built on code from Kraeutmann, sorry for the mis-attribution.
On Sat, May 18, 2019 at 8:34 AM Thomas DuBuisson
<thomas.dubuisson at gmail.com> wrote:
>
> On Sat, May 18, 2019 at 2:56 AM Magicloud Magiclouds
> <magicloud.magiclouds at gmail.com> wrote:
> >
> > Thanks. Just to make it clear, the code is for generating candidates,
> > not the answer, right? From first glance, the code shows a lot
> > solutions that do not sum to 10. Have not check if it contains all
> > answers.
>
> They were the right answers for each index. N.B. the comment
> -- A list of all sets of numbers, no duplicates and ignoring order,
> -- that sum to the value @index + 1 at .
>
> I'm glad to hear you only want the answer for 10 and the DP aspect
> isn't supposed to re-use sum sets for values 1..9 to construct sums
> for 10 (which is what I did, it was ugly and slow). In that case you
> can use Ariis's awesome solution with very minor modification:
>
> ```
> import Data.List
>
> main = print answer
>
> type Solution = [Integer]
>
> answer = sums 10
>
> sums :: Integer -> [Solution]
> sums n = do
> x <- [1..n] -- Pick a largest number in the same
> go x [x] (n - x) -- recursively pass the smallest value, the
> current solution, and remainder
> where
> go x xs r
> | r > 0 && x == 1 = fail "" -- If there is a
> remainder and we've already used 1 this isn't a soluton
> | r > 0 = do x <- [1..min (x-1) r] -- The next value must be
> between 1 and the min of remainder and one-less than the last pick
> go x (x:xs) (r - x)
> | otherwise = return xs
> ```
>
> -Thomas
>
> >
> > On Sat, May 18, 2019 at 3:03 PM Thomas DuBuisson
> > <thomas.dubuisson at gmail.com> wrote:
> > >
> > > As an aside: I feel certain I saw a beautiful solution presented as
> > > lecture notes and referencing a game show (around 2007). Maybe it was
> > > in Hudak's book?
> > >
> > >
> > > Perhaps I missed something, but the answer's I've seen posted thus far
> > > are not dynamic programming. Certainly in the powerset case you'll
> > > experience exponential costs. Benchmarks are good - try to solve with
> > > numbers [1..64] in low numbers of seconds.
> > >
> > > An explicit 98-ish solution is to have a generator that will refer to
> > > the prior indexes in the list when computing the current index.
> > >
> > >
> > > First the boiler plate:
> > >
> > > ```
> > > {-# LANGUAGE OverloadedLists #-}
> > > module Main where
> > >
> > > import qualified Data.Set as Set
> > > import Control.Monad (guard)
> > >
> > > type Solution = Set.Set Int
> > >
> > > -- A list of all sets of numbers, no duplicates and ignoring order,
> > > -- that sum to the value @index + 1 at .
> > > answer :: [[Solution]]
> > > answer = fmap op [1..10]
> > > where
> > > ```
> > >
> > > Now for the interesting part. The recursive definition of a solution
> > > for value `target` is `[target]` and the solutions for `x` added with
> > > the solution for `target - x` where `x <- [0..target/2]. Some care
> > > must be taken because solutions will overlap.
> > >
> > > With that in mind:
> > >
> > > ```
> > > -- Generate the entry for value @target@ (list index @target - 1@)
> > > op :: Int -> [Solution]
> > > op target =
> > > ([target] :: Solution) -- The target itself is an answer
> > > : snub -- Ignore duplicate results
> > > -- Better idea: don't
> > > generate dups if you can...
> > > (do let half = target `div` 2
> > > halfRDown = (target-1) `div` 2
> > > (ls,hs) <- zip (slice 0 half answer) -- Pair 0 .. t/2
> > > -- with t-1, t-2 .. t/2+1
> > > (reverse $ slice half halfRDown answer)
> > > l <- ls -- For each solution to the lower number
> > > h <- hs -- and the matching solution to the larger number
> > > guard (Set.intersection l h == []) -- No repeat values! (?)
> > > pure (l <> h) -- target = l + h
> > > )
> > >
> > > -- | List slice from a base and of given length
> > > slice :: Int -> Int -> [a] -> [a]
> > > slice base len = take len . drop base
> > >
> > > -- | Efficient combined sort and nub
> > > snub :: (Eq a, Ord a) => [a] -> [a]
> > > snub = Set.toList . Set.fromList
> > >
> > > main :: IO ()
> > > main = print answers
> > > ```
> > >
> > > -Thomas
> > >
> > >
> > > On Fri, May 17, 2019 at 9:35 PM Magicloud Magiclouds
> > > <magicloud.magiclouds at gmail.com> wrote:
> > > >
> > > > Hi,
> > > >
> > > > I solved the question. But I could not figure out a FP style solution.
> > > >
> > > > Question:
> > > >
> > > > 1 - 9, nine numbers. Show all the possible combinations that sum up to
> > > > 10. Different orders are counted as the same.
> > > >
> > > > For example, [1, 4, 5].
> > > > _______________________________________________
> > > > Haskell-Cafe mailing list
> > > > To (un)subscribe, modify options or view archives go to:
> > > > http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe
> > > > Only members subscribed via the mailman list are allowed to post.
More information about the Haskell-Cafe
mailing list