Skip to content

Commit 0375fc5

Browse files
committed
Add demo examples
1 parent 4131bc2 commit 0375fc5

File tree

2 files changed

+109
-0
lines changed

2 files changed

+109
-0
lines changed

12.memo1.hs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import Data.List (nub, intercalate)
2+
import Data.Map qualified as M
3+
4+
-- The manually memoized (without using the State monad) variation of 12.hs.
5+
--
6+
-- This doesn't actually do any memoization, it is a stepping stone to the real
7+
-- version. This is a part of a demonstration showing how we go from an
8+
-- unmemoized version (12.unmemo.hs) to a memoized version using the (State)
9+
-- monad (12.hs).
10+
11+
main :: IO ()
12+
main = interact $ (++ "\n") . show . p2 . parse
13+
14+
parse :: String -> [(String, [Int])]
15+
parse = map line . lines
16+
where
17+
line l = case words l of
18+
[s, num] -> (s, map read $ words $ map comma num)
19+
comma c = if c == ',' then ' ' else c
20+
21+
p1, p2 :: [(String, [Int])] -> Int
22+
p1 = sum . map ways
23+
p2 = p1 . unfold
24+
25+
unfold :: [(String, [Int])] -> [(String, [Int])]
26+
unfold = map f
27+
where f (s, xs) = (intercalate "?" (replicate 5 s), concat (replicate 5 xs))
28+
29+
type Rx = (String, [Int])
30+
type Memo = M.Map Rx Int
31+
32+
ways :: Rx -> Int
33+
ways = ways' memo M.empty
34+
where memo m k = ways' memo m k
35+
36+
ways' :: (Memo -> Rx -> Int) -> Memo -> Rx -> Int
37+
ways' f m ([], []) = 1
38+
ways' f m ([], [x]) = 0
39+
ways' f m (s, []) = if none '#' s then 1 else 0
40+
ways' f m (('.':rs), xs) = f m (rs, xs)
41+
ways' f m (('?':rs), xs) = f m (rs, xs) + f m (('#':rs), xs)
42+
ways' f m (s, (x:rx)) | length s >= x && none '.' (take x s) && notAfter x '#' s
43+
= f m ((drop (x + 1) s), rx)
44+
ways' _ _ _ = 0
45+
46+
notAfter :: Int -> Char -> String -> Bool
47+
notAfter x c s = none c (take 1 (drop x s))
48+
49+
only, none :: Char -> String -> Bool
50+
only c = all (== c) . nub
51+
none c = not . any (== c) . nub

12.memo2.hs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import Data.List (nub, intercalate)
2+
import Data.Map qualified as M
3+
4+
-- The manually memoized (without using the State monad) variation of 12.hs.
5+
--
6+
-- This builds up from step 1 (12.memo1.hs), and adds the actual map lookup and
7+
-- insertion to memoize the results. The final version (12.hs) just abstracts
8+
-- this handling under the State monad.
9+
10+
main :: IO ()
11+
main = interact $ (++ "\n") . show . p2 . parse
12+
13+
parse :: String -> [(String, [Int])]
14+
parse = map line . lines
15+
where
16+
line l = case words l of
17+
[s, num] -> (s, map read $ words $ map comma num)
18+
comma c = if c == ',' then ' ' else c
19+
20+
p1, p2 :: [(String, [Int])] -> Int
21+
p1 = sum . map ways
22+
p2 = p1 . unfold
23+
24+
unfold :: [(String, [Int])] -> [(String, [Int])]
25+
unfold = map f
26+
where f (s, xs) = (intercalate "?" (replicate 5 s), concat (replicate 5 xs))
27+
28+
type Rx = (String, [Int])
29+
type Memo = M.Map Rx Int
30+
31+
ways :: Rx -> Int
32+
ways = snd . ways' memo M.empty
33+
where
34+
-- Uncomment this to see a version that doesn't do any memoization
35+
--memo m k = ways' memo m k
36+
-- This one does the lookup + insertion which serves as our memoization
37+
memo m k = case M.lookup k m of
38+
Just v -> (m, v)
39+
Nothing -> let (m', v) = ways' memo m k in (M.insert k v m', v)
40+
41+
ways' :: (Memo -> Rx -> (Memo, Int)) -> Memo -> Rx -> (Memo, Int)
42+
ways' f m ([], []) = (m, 1)
43+
ways' f m ([], [x]) = (m, 0)
44+
ways' f m (s, []) = if none '#' s then (m, 1) else (m, 0)
45+
ways' f m (('.':rs), xs) = f m (rs, xs)
46+
ways' f m (('?':rs), xs) = let (m1, v1) = f m (rs, xs)
47+
(m2, v2) = f m1 (('#':rs), xs)
48+
in (m2, v1 + v2)
49+
ways' f m (s, (x:rx)) | length s >= x && none '.' (take x s) && notAfter x '#' s
50+
= f m ((drop (x + 1) s), rx)
51+
ways' _ m _ = (m, 0)
52+
53+
notAfter :: Int -> Char -> String -> Bool
54+
notAfter x c s = none c (take 1 (drop x s))
55+
56+
only, none :: Char -> String -> Bool
57+
only c = all (== c) . nub
58+
none c = not . any (== c) . nub

0 commit comments

Comments
 (0)