quiz : 解答編 : Concurrent Clean : ソースコード

出力は、最終結果だけでなく、計算過程も出力するようにしています。

module Main

import StdEnv, OptEnv

// utility
(-->|) infixl 0
(-->|) a (p,f) :== if p (f a) a

interleave as bs :== il1 as bs
  where
    il1 []     _  = []
    il1 [a:ar] bs = [a:il2 ar bs]

    il2 _  []     = []
    il2 as [b:br] = [b:il1 as br]

// main routine
Start :: *World -> *World
Start w
    # (f,w) = stdio w
    # f = f
        --> (align ns as --> map (fwritess o draw)
                         --> reverse
                         --> flip interleave $ repeat $ fwrites "---------\n"
                         --> reelU)
        //--> fwritess $ draw $ hd $ align ns as
    # (ok, w) = fclose f w
    = w
  where
    //ns = [1,2,3,4]
    //as = [(1,2),(1,3),(1,4),(2,4),(3,4)]
    ns = [1,2,3,4,5,6,7,8]
    as = [(1,6),(6,8),(1,2),(2,3),(2,4),(3,5),(4,7),(5,8),(7,8)]
    //ns = [1,2,3,4,5,6,7]
    //as = [(1,2),(1,4),(1,7),(2,3),(3,5),(4,5),(5,6),(5,7),(6,7)]
    //ns = [1,2,3,4]
    //as = [(1,2),(2,4),(1,3),(3,4)]


charset :: {Char}
charset =: {a \\ a <- ['0'..'9'] ++ ['a'..'z'] ++ ['A'..'Z']}

::Node :== Int
::Arc :== (!Node,!Node)
::Point :== (!Int,!Int)
::Cell :== (!Node,!Point)

showNode :: Node -> Char
showNode n = charset.[n]

draw :: [Cell] -> [String]
draw g = drawCanvas g canvas
  where
    (mX, mY) = foldl (\(x0,y0) (_,(x1,y1)) = (max x0 x1, max y0 y1)) (0,0) g

    canvas :: [String]
    canvas = let line = {' ' \\ j <- [0..mX]} in [line \\ i <- [0..mY]]

    drawCanvas :: [Cell] [String] -> [String]
    drawCanvas [] cv = cv
    drawCanvas [(n,(x,y)):gr] cv = drawCanvas gr $ updateAt y (cv!!y := (x, showNode n)) cv

fwritess :: [String] *File -> *File
fwritess ss f = f --> reelU $ map (\s f = f <<< s <<< "\n") ss


align :: [Node] [Arc] -> [[Cell]]
align nodes arcs = initCell --> alignY --> alignX
  where
    preNodes :: Node -> [Node]
    preNodes n = map fst $ filter (\a = n == snd a) arcs

    postNodes :: Node -> [Node]
    postNodes n = map snd $ filter (\a = n == fst a) arcs

    toCell :: [Cell] Node -> Cell
    toCell cs n = case filter (\(m,_) = m == n) cs of
                    []    = abort $ "error at toCell of " +++ toString n
                    [a:_] = a

    toPoint :: [Cell] Node -> Point
    toPoint cs n = snd $ toCell cs n

    initCell :: [Cell]
    initCell = [(n,(i,0)) \\ n <- nodes & i <|- [!0..]]

    alignY :: [Cell] -> [[Cell]]
    alignY cs = (\(_,r,_) = r) $ alignY (last cs) (0, [cs], [])
      where
        updateCell (n,p) [] = []
        updateCell (n,p) [(m,q):cr] | n == m = [(n,p):cr]
                                             = [(m,q):updateCell (n,p) cr]

        alignY :: Cell (Int, [[Cell]], [Node]) -> (Int, [[Cell]], [Node])
        alignY c=:(n,(x,y)) (lbl, css=:[cs:_], ns) = (lbl, css2, [n:ns])
                                                             --> (pns --> map alignY
                                                                      --> flip interleave (repeat inclbl)
                                                                      --> init
                                                                      --> reelU)
          where
            pns = map (toCell cs2) $ filter (not o (flip isMember ns)) $ preNodes n
            cs2 = updateCell (n,(x,lbl)) cs
            css2 = [cs2:css]
            inclbl (l,c,n) = (inc l,c,n)

    alignX :: [[Cell]] -> [[Cell]]
    alignX css=:[cs:csr] = alignX 0 [cs:css]
      where
        len = length cs

        alignX :: Int [[Cell]] -> [[Cell]]
        alignX i css=:[cs:csr] | i < len = alignX (inc i) [(updateAt i (n,(x2,y)) cs):csr]
                                         = css
          where
            (n,(x,y)) = cs!!i
            x2 = case preNodes n of
                   [] = x
                   ps = inc $ maxList $ map (fst o (toPoint cs)) ps