Concurrent Clean : あなたならどうお書きになります1.0

[id:lethevert:20061222:p5]
この間のあれは、何も考えずに書いたので、当然ながら効率は悪い。
手元のPCで、8人までは1秒以内だったが、9人で5秒。10人以上ではメモリも時間もかなりかかってしまう。
そこで、別のアプローチに切り替えて書き直してみよう。

      • -

とりあえず、こんな。20要素でも1秒以内に結果が返ってきます。
解なしの可能性を考えて、試行回数を30回に制限しています。
ところで、shuffle関数は、OptEnvに含めてしまおうかと思っています。

import StdEnv, OptEnv, MersenneTwister

/* an imperative perfect shuffle algorithm
 * according to http://okmij.org/ftp/Haskell/
 */
shuffle :: [a] [Int] -> ([a],[Int])
shuffle ls rnd # arr = asArray {a \\ a <- ls}
                 (n, arr) = usize arr
                 n = dec n
                 (arr,rnd) = shuffle n rnd arr
               = ([a \\ a <-: arr], rnd)
  where
    shuffle n rnd arr | n <= 0 = (arr,rnd)
    shuffle n [r:rnd] arr = shuffle (dec n) rnd (swap ((abs r) rem n) arr)
      where
        swap i arr=:{[i]=ai,[n]=an} = {arr & [i]=an,[n]=ai}

shuffle2 ls rnd = shuffle2 rnd
  where
    shuffle2 rnd # (ls2, rnd) = shuffle ls rnd
                 = [ls2:shuffle2 rnd]

::Person = Person !Char !Int
instance == Person where
  (==) (Person g1 p1) (Person g2 p2) = g1 == g2 && p1 == p2

answer trial ps rnd = filter f $ map (zip2 ps) $ take trial $ shuffle2 ps rnd
  where
    f [] = True
    f [(Person g1 _,Person g2 _):rest] = g1 <> g2 && f rest

Start w # (t,w) = tick_count w
        = case answer 30 case20 (genRandInt t) of
            []  = Nothing
            ans = Just (hd ans)