module MPSExtra where

-- import Text.Template
-- import Text.Pandoc
import Data.Graph.Inductive (Gr, mkGraph)
import qualified Data.Graph as G
import MPS hiding ((>))
import Prelude hiding ((.))
import Data.List (sort)

-- 
-- interpolate :: String -> [(String, String)] -> String
-- interpolate s params = B.unpack $ substitute (B.pack s) (context params)
--   where 
--     context = map packPair >>> to_h
--     packPair (x, y) = (B.pack x, B.pack y)

-- -- QuickCheck
-- quick_check prop = quickCheck prop
-- qc prop          = quick_check prop

-- 
-- -- Text
-- markdown = b2u > readMarkdown defaultParserState > writeHtml defaultWriterOptions
-- markdown' = b2u > readMarkdown defaultParserState > writeHtmlString defaultWriterOptions > u2b


-- Graph1
to_g'' = G.buildG 


-- Graph2
type GType = Int
to_g_with :: Real a => (GType -> c) -> [(GType, GType, a)] -> Gr c a
to_g_with mapper xs = mkGraph (xs.label_nodes) xs where
  node_pair x       = (x, mapper x) 
  label_nodes xs    = xs.map(\(a,b,_) -> [a,b]) .join' .unique .map node_pair

to_g xs             = to_g_with id xs

graph_map xs        = (edges, vertex_map) where
  vertices          = xs.map(\(a,b,_)-> [a,b]).join'.unique.sort
  vertex_map        = vertices.indexed
  r_vertex_map      = vertex_map.map(swap)
  edges             = xs.map(\(a,b,c) -> (r_vertex_map.lookup' a, r_vertex_map.lookup' b, c))

to_g' xs            = let (edges, vertex_map) = graph_map xs in
  edges.to_g_with (vertex_map.flip lookup')
  



-- Greedy
greedy_count x xs = greedy x xs .length

greedy x xs = greedy' x (xs.rsort) where
  greedy' x _ | x < 0 = [[]]
  greedy' 0 _        = [[]]
  greedy' x [y]       = if (x `mod` y) .is 0 then [ (x `div` y).from_i .times y ] else [[]]
  greedy' s (a:as)    = [ h ++ t |
    n <- [0..(div s a)].reverse,
    let h = n.from_i.times a,
    t <- greedy' (s - n * a) as,
    let c = h ++ t,
    c.sum == s
    ]
  greedy' _ _ = error "argument type"



-- Matrix
row n i = i `div` n
col n i = i `mod` n
m !!! i = m.at(row n i) .at(col n i) 
  where n = m.first.length
-- Runtime
-- eval_with libs s = Eval.unsafeEval s libs.purify.fromJust
-- eval s           = eval_with s []



-- Algorithm
-- DP

-- OK usage is a bit tricky
-- xs.cache block where
--   block a list = closure
-- The idea is to bound a in your closure
-- what is this a anyway?
-- It's an array that lazily caches the result
-- from your list processing function, i.e. what's
-- inside your closure.
-- This implies that your processing function
-- is of type: [x] -> [x]


cache f xs = a.to_list where
  a = xs.g.to_a
  g ys = f a ys