Day5, add SortedMap
This commit is contained in:
4
TODO.md
4
TODO.md
@@ -1,6 +1,10 @@
|
|||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
|
- [ ] fix "insufficient patterns", wire in M or Either String
|
||||||
|
- [ ] typeclass dependencies
|
||||||
|
- need to flag internal functions to not search (or flag functions for search)
|
||||||
|
- don't search instances that are currently being defined
|
||||||
- [ ] syntax for negative integers
|
- [ ] syntax for negative integers
|
||||||
- [x] Put worker in iframe on safari
|
- [x] Put worker in iframe on safari
|
||||||
- [ ] Warnings or errors for missing definitions
|
- [ ] Warnings or errors for missing definitions
|
||||||
|
|||||||
@@ -2,6 +2,10 @@ module Aoc
|
|||||||
|
|
||||||
import Prelude
|
import Prelude
|
||||||
|
|
||||||
|
-- `by` is the first argument for use in `map`
|
||||||
|
nums' : String → String → List Int
|
||||||
|
nums' by s = map stringToInt $ filter (_/=_ "") $ split (trim s) by
|
||||||
|
|
||||||
nums : String → List Int
|
nums : String → List Int
|
||||||
nums s = map stringToInt $ filter (_/=_ "") $ split (trim s) " "
|
nums s = map stringToInt $ filter (_/=_ "") $ split (trim s) " "
|
||||||
|
|
||||||
@@ -25,13 +29,3 @@ indexOf? {a} z xs = go Z z xs
|
|||||||
go ix z Nil = Nothing
|
go ix z Nil = Nothing
|
||||||
go ix z (x :: xs) =
|
go ix z (x :: xs) =
|
||||||
if z == x then Just ix else go (S ix) z xs
|
if z == x then Just ix else go (S ix) z xs
|
||||||
|
|
||||||
-- if_then_else shorthand
|
|
||||||
-- Lean version uses a decidable instead of Bool
|
|
||||||
ite : ∀ a. Bool → a → a → a
|
|
||||||
ite c t e = if c then t else e
|
|
||||||
|
|
||||||
-- probably not super efficient, but it works
|
|
||||||
qsort : ∀ a. (a → a → Bool) → List a → List a
|
|
||||||
qsort lt Nil = Nil
|
|
||||||
qsort lt (x :: xs) = qsort lt (filter (λ y => not $ lt x y) xs) ++ x :: qsort lt (filter (lt x) xs)
|
|
||||||
|
|||||||
@@ -21,12 +21,8 @@ check prob r c (dr,dc) =
|
|||||||
else if (get prob (r + 3 * dr) (c + 3 * dc)) /= 'S' then 0
|
else if (get prob (r + 3 * dr) (c + 3 * dc)) /= 'S' then 0
|
||||||
else 1
|
else 1
|
||||||
|
|
||||||
tail : ∀ a. List a → List a
|
|
||||||
tail Nil = Nil
|
|
||||||
tail (x :: xs) = xs
|
|
||||||
|
|
||||||
dirs : List (Int × Int)
|
dirs : List (Int × Int)
|
||||||
dirs = tail $ _,_ <$> (0 :: 0 - 1 :: 1 :: Nil) <*> (0 :: 0 - 1 :: 1 :: Nil)
|
dirs = tail $ _,_ <$> 0 :: 0 - 1 :: 1 :: Nil <*> 0 :: 0 - 1 :: 1 :: Nil
|
||||||
|
|
||||||
part1 : Problem → Int
|
part1 : Problem → Int
|
||||||
part1 (P size text) = go 0 0 0
|
part1 (P size text) = go 0 0 0
|
||||||
@@ -70,7 +66,6 @@ run fn = do
|
|||||||
text <- readFile fn
|
text <- readFile fn
|
||||||
let lines = split (trim text) "\n"
|
let lines = split (trim text) "\n"
|
||||||
-- I'm going to assume it's square for convenience
|
-- I'm going to assume it's square for convenience
|
||||||
-- part2 will probably wrap around.
|
|
||||||
let size = length lines
|
let size = length lines
|
||||||
printLn $ "part1 " ++ show (part1 $ P (cast size) text)
|
printLn $ "part1 " ++ show (part1 $ P (cast size) text)
|
||||||
printLn $ "part2 " ++ show (part2 $ P (cast size) text)
|
printLn $ "part2 " ++ show (part2 $ P (cast size) text)
|
||||||
|
|||||||
77
aoc2024/Day5.newt
Normal file
77
aoc2024/Day5.newt
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
module Day5
|
||||||
|
|
||||||
|
import Prelude
|
||||||
|
import Node
|
||||||
|
import Aoc
|
||||||
|
import SortedMap
|
||||||
|
|
||||||
|
data Prob : U where
|
||||||
|
MkProb : List (Int × Int) -> List (List Int) → Prob
|
||||||
|
|
||||||
|
parseRule : String → Maybe (Int × Int)
|
||||||
|
parseRule txt =
|
||||||
|
let (a :: b :: Nil) = nums' "|" txt | _ => Nothing
|
||||||
|
in Just (a,b)
|
||||||
|
|
||||||
|
parse : String → Maybe Prob
|
||||||
|
parse text = do
|
||||||
|
let (a :: b :: Nil) = split (trim text) "\n\n" | pts => Nothing
|
||||||
|
rules <- traverse parseRule $ split a "\n"
|
||||||
|
let updates = map (nums' ",") $ split b "\n"
|
||||||
|
Just $ MkProb rules updates
|
||||||
|
|
||||||
|
RuleMap : U
|
||||||
|
RuleMap = SortedMap Int (List Int)
|
||||||
|
|
||||||
|
getDisallowed : Int → RuleMap → List Int
|
||||||
|
getDisallowed key rmap = fromMaybe Nil (map snd $ lookupMap key rmap)
|
||||||
|
|
||||||
|
mkRuleMap : List (Int × Int) -> RuleMap
|
||||||
|
mkRuleMap rules = foldl go EmptyMap rules
|
||||||
|
where
|
||||||
|
go : RuleMap → Int × Int → RuleMap
|
||||||
|
go rmap (b,a) = updateMap a (b :: getDisallowed a rmap) rmap
|
||||||
|
|
||||||
|
scan : RuleMap → List Int -> List Int -> Bool
|
||||||
|
scan rmap interdit Nil = True
|
||||||
|
scan rmap interdit (x :: xs) =
|
||||||
|
if elem x interdit then False
|
||||||
|
else scan rmap (getDisallowed x rmap ++ interdit) xs
|
||||||
|
|
||||||
|
fix : RuleMap → List Int → List Int
|
||||||
|
fix rmap Nil = Nil
|
||||||
|
fix rmap (x :: xs) =
|
||||||
|
let interdit = getDisallowed x rmap in
|
||||||
|
let (prefix,rest) = partition (flip elem interdit) xs
|
||||||
|
in case prefix of
|
||||||
|
Nil => x :: fix rmap rest
|
||||||
|
ys => fix rmap (ys ++ x :: rest)
|
||||||
|
|
||||||
|
middle : List Int -> Int
|
||||||
|
middle xs = go xs xs
|
||||||
|
where
|
||||||
|
go : List Int → List Int → Int
|
||||||
|
go (x :: xs) (_ :: _ :: ys) = go xs ys
|
||||||
|
go (x :: xs) (_ :: ys) = x
|
||||||
|
go _ _ = 0
|
||||||
|
|
||||||
|
run : String -> IO Unit
|
||||||
|
run fn = do
|
||||||
|
putStrLn fn
|
||||||
|
text <- readFile fn
|
||||||
|
let (Just prob) = parse text | _ => putStrLn "Parse Error"
|
||||||
|
let (MkProb rules things) = prob
|
||||||
|
let rmap = mkRuleMap rules
|
||||||
|
let good = filter (scan rmap Nil) things
|
||||||
|
let part1 = foldl _+_ 0 $ map middle good
|
||||||
|
let bad = filter (not ∘ scan rmap Nil) things
|
||||||
|
putStrLn $ "part1 " ++ show part1
|
||||||
|
let fixed = map (fix rmap) bad
|
||||||
|
printLn $ length bad
|
||||||
|
let part2 = foldl _+_ 0 $ map middle fixed
|
||||||
|
putStrLn $ "part2 " ++ show part2
|
||||||
|
|
||||||
|
main : IO Unit
|
||||||
|
main = do
|
||||||
|
run "aoc2024/day5/eg.txt"
|
||||||
|
run "aoc2024/day5/input.txt"
|
||||||
17
aoc2024/DayXX.newt
Normal file
17
aoc2024/DayXX.newt
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
module DayXX
|
||||||
|
|
||||||
|
import Prelude
|
||||||
|
import Node
|
||||||
|
import Aoc
|
||||||
|
|
||||||
|
|
||||||
|
run : String -> IO Unit
|
||||||
|
run fn = do
|
||||||
|
putStrLn fn
|
||||||
|
text <- readFile fn
|
||||||
|
putStrLn text
|
||||||
|
|
||||||
|
main : IO Unit
|
||||||
|
main = do
|
||||||
|
run "aoc2024/dayXX/eg.txt"
|
||||||
|
run "aoc2024/dayXX/input.txt"
|
||||||
58
aoc2024/SortedMap.newt
Normal file
58
aoc2024/SortedMap.newt
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
module SortedMap
|
||||||
|
|
||||||
|
data T23 : Nat -> U -> U -> U where
|
||||||
|
Leaf : ∀ k v. k -> v -> T23 Z k v
|
||||||
|
Node2 : ∀ h k v. T23 h k v -> k -> T23 h k v -> T23 (S h) k v
|
||||||
|
Node3 : ∀ h k v. T23 h k v -> k -> T23 h k v -> k -> T23 h k v -> T23 (S h) k v
|
||||||
|
|
||||||
|
lookupT23 : ∀ h k v. {{Ord k}} {{Eq k}} -> k -> T23 h k v -> Maybe (k × v)
|
||||||
|
lookupT23 key (Leaf k v)= if k == key then Just (k,v) else Nothing
|
||||||
|
lookupT23 key (Node2 t1 k1 t2) =
|
||||||
|
if key <= k1 then lookupT23 key t1 else lookupT23 key t2
|
||||||
|
lookupT23 key (Node3 t1 k1 t2 k2 t3) =
|
||||||
|
if key <= k1 then lookupT23 key t1
|
||||||
|
else if key <= k2 then lookupT23 key t2
|
||||||
|
else lookupT23 key t3
|
||||||
|
|
||||||
|
insertT23 : ∀ h k v. {{Ord k}} {{Eq k}} -> k -> v -> T23 h k v -> Either (T23 h k v) (T23 h k v × k × T23 h k v)
|
||||||
|
insertT23 key value (Leaf k v) =
|
||||||
|
if key == k then Left (Leaf key value)
|
||||||
|
else if key <= k then Right (Leaf key value, key, Leaf k v)
|
||||||
|
else Right (Leaf k v, k, Leaf key value)
|
||||||
|
insertT23 key value (Node2 t1 k1 t2) =
|
||||||
|
if key <= k1 then
|
||||||
|
case insertT23 key value t1 of
|
||||||
|
Left t1' => Left (Node2 t1' k1 t2)
|
||||||
|
Right (a,b,c) => Left (Node3 a b c k1 t2)
|
||||||
|
else case insertT23 key value t2 of
|
||||||
|
Left t2' => Left (Node2 t1 k1 t2')
|
||||||
|
Right (a,b,c) => Left (Node3 t1 k1 a b c)
|
||||||
|
insertT23 key value (Node3 t1 k1 t2 k2 t3) =
|
||||||
|
if key <= k1 then
|
||||||
|
case insertT23 key value t1 of
|
||||||
|
Left t1' => Left (Node3 t1' k1 t2 k2 t3)
|
||||||
|
Right (a,b,c) => Right (Node2 a b c, k1, Node2 t2 k2 t3)
|
||||||
|
else if key <= k2 then
|
||||||
|
case insertT23 key value t2 of
|
||||||
|
Left t2' => Left (Node3 t1 k1 t2' k2 t3)
|
||||||
|
Right (a,b,c) => Right (Node2 t1 k1 a, b, Node2 c k2 t3)
|
||||||
|
else
|
||||||
|
case insertT23 key value t3 of
|
||||||
|
Left t3' => Left (Node3 t1 k1 t2 k2 t3')
|
||||||
|
Right (a,b,c) => Right (Node2 t1 k1 t2, k2, Node2 a b c)
|
||||||
|
|
||||||
|
-- There is no empty tree23?
|
||||||
|
data SortedMap : U -> U -> U where
|
||||||
|
EmptyMap : ∀ k v. SortedMap k v
|
||||||
|
MapOf : ∀ k v h. T23 h k v -> SortedMap k v
|
||||||
|
|
||||||
|
lookupMap : ∀ k v. {{Ord k}} {{Eq k}} -> k -> SortedMap k v -> Maybe (k × v)
|
||||||
|
lookupMap k EmptyMap = Nothing
|
||||||
|
lookupMap k (MapOf map) = lookupT23 k map
|
||||||
|
|
||||||
|
updateMap : ∀ k v. {{Ord k}} {{Eq k}} -> k -> v -> SortedMap k v -> SortedMap k v
|
||||||
|
updateMap k v EmptyMap = MapOf $ Leaf k v
|
||||||
|
updateMap k v (MapOf map) = case insertT23 k v map of
|
||||||
|
Left map' => MapOf map'
|
||||||
|
Right (a, b, c) => MapOf (Node2 a b c)
|
||||||
|
|
||||||
28
aoc2024/day5/eg.txt
Normal file
28
aoc2024/day5/eg.txt
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
47|53
|
||||||
|
97|13
|
||||||
|
97|61
|
||||||
|
97|47
|
||||||
|
75|29
|
||||||
|
61|13
|
||||||
|
75|53
|
||||||
|
29|13
|
||||||
|
97|29
|
||||||
|
53|29
|
||||||
|
61|53
|
||||||
|
97|53
|
||||||
|
61|29
|
||||||
|
47|13
|
||||||
|
75|47
|
||||||
|
97|75
|
||||||
|
47|61
|
||||||
|
75|61
|
||||||
|
47|29
|
||||||
|
75|13
|
||||||
|
53|13
|
||||||
|
|
||||||
|
75,47,61,53,29
|
||||||
|
97,61,53,29,13
|
||||||
|
75,29,13
|
||||||
|
75,97,47,61,53
|
||||||
|
61,13,29
|
||||||
|
97,13,75,29,47
|
||||||
7
aoc2024/mkday
Executable file
7
aoc2024/mkday
Executable file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/zsh -e
|
||||||
|
day=$1
|
||||||
|
if [ ! -d day${day} -a ! -z "$1" ]; then
|
||||||
|
echo Make Day ${day}
|
||||||
|
mkdir day${day}
|
||||||
|
sed "s/XX/$day/g" DayXX.newt > Day$day.newt
|
||||||
|
fi
|
||||||
@@ -91,18 +91,6 @@ fst (a,b) = a
|
|||||||
|
|
||||||
snd : ∀ a b. a × b → b
|
snd : ∀ a b. a × b → b
|
||||||
snd (a,b) = b
|
snd (a,b) = b
|
||||||
|
|
||||||
infixl 6 _<_ _<=_
|
|
||||||
class Ord a where
|
|
||||||
_<_ : a → a → Bool
|
|
||||||
|
|
||||||
instance Ord Nat where
|
|
||||||
_ < Z = False
|
|
||||||
Z < S _ = True
|
|
||||||
S n < S m = n < m
|
|
||||||
|
|
||||||
_<=_ : ∀ a. {{Eq a}} {{Ord a}} → a → a → Bool
|
|
||||||
a <= b = a == b || a < b
|
|
||||||
-- Monad
|
-- Monad
|
||||||
|
|
||||||
class Monad (m : U → U) where
|
class Monad (m : U → U) where
|
||||||
@@ -348,11 +336,6 @@ class HasIO (m : U -> U) where
|
|||||||
instance HasIO IO where
|
instance HasIO IO where
|
||||||
liftIO a = a
|
liftIO a = a
|
||||||
|
|
||||||
pfunc debugLog uses (MkIORes MkUnit) : ∀ a. a -> IO Unit := `(_,s) => (w) => {
|
|
||||||
console.log(s)
|
|
||||||
return MkIORes(undefined,MkUnit,w)
|
|
||||||
}`
|
|
||||||
|
|
||||||
pfunc primPutStrLn uses (MkIORes MkUnit) : String -> IO Unit := `(s) => (w) => {
|
pfunc primPutStrLn uses (MkIORes MkUnit) : String -> IO Unit := `(s) => (w) => {
|
||||||
console.log(s)
|
console.log(s)
|
||||||
return MkIORes(undefined,MkUnit,w)
|
return MkIORes(undefined,MkUnit,w)
|
||||||
@@ -387,7 +370,6 @@ pfunc pack : List Char → String := `(cs) => {
|
|||||||
rval += cs.h1
|
rval += cs.h1
|
||||||
cs = cs.h2
|
cs = cs.h2
|
||||||
}
|
}
|
||||||
|
|
||||||
return rval
|
return rval
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
@@ -415,6 +397,9 @@ pfunc debugStr uses (natToInt listToArray) : ∀ a. a → String := `(_, obj) =>
|
|||||||
return go(obj)
|
return go(obj)
|
||||||
}`
|
}`
|
||||||
|
|
||||||
|
debugLog : ∀ a. a → IO Unit
|
||||||
|
debugLog a = putStrLn (debugStr a)
|
||||||
|
|
||||||
pfunc stringToInt : String → Int := `(s) => {
|
pfunc stringToInt : String → Int := `(s) => {
|
||||||
let rval = Number(s)
|
let rval = Number(s)
|
||||||
if (isNaN(rval)) throw new Error(s + " is NaN")
|
if (isNaN(rval)) throw new Error(s + " is NaN")
|
||||||
@@ -444,9 +429,6 @@ instance Add Int where
|
|||||||
instance Sub Int where
|
instance Sub Int where
|
||||||
x - y = subInt x y
|
x - y = subInt x y
|
||||||
|
|
||||||
instance Ord Int where
|
|
||||||
x < y = ltInt x y
|
|
||||||
|
|
||||||
printLn : {m} {{HasIO m}} {a} {{Show a}} → a → m Unit
|
printLn : {m} {{HasIO m}} {a} {{Show a}} → a → m Unit
|
||||||
printLn a = putStrLn (show a)
|
printLn a = putStrLn (show a)
|
||||||
|
|
||||||
@@ -633,3 +615,63 @@ instance Applicative List where
|
|||||||
return a = a :: Nil
|
return a = a :: Nil
|
||||||
Nil <*> _ = Nil
|
Nil <*> _ = Nil
|
||||||
fs <*> ys = join $ map (\ f => map f ys) fs
|
fs <*> ys = join $ map (\ f => map f ys) fs
|
||||||
|
|
||||||
|
tail : ∀ a. List a → List a
|
||||||
|
tail Nil = Nil
|
||||||
|
tail (x :: xs) = xs
|
||||||
|
|
||||||
|
--
|
||||||
|
|
||||||
|
infixl 6 _<_ _<=_
|
||||||
|
class Ord a where
|
||||||
|
-- isEq : Eq a
|
||||||
|
_<_ : a → a → Bool
|
||||||
|
|
||||||
|
_<=_ : ∀ a. {{Eq a}} {{Ord a}} → a → a → Bool
|
||||||
|
a <= b = a == b || a < b
|
||||||
|
|
||||||
|
|
||||||
|
search : ∀ cl. {{cl}} -> cl
|
||||||
|
search {{x}} = x
|
||||||
|
|
||||||
|
instance Ord Nat where
|
||||||
|
-- isEq = search
|
||||||
|
_ < Z = False
|
||||||
|
Z < S _ = True
|
||||||
|
S n < S m = n < m
|
||||||
|
|
||||||
|
|
||||||
|
instance Ord Int where
|
||||||
|
-- isEq = ?
|
||||||
|
x < y = ltInt x y
|
||||||
|
|
||||||
|
-- foo : ∀ a. {{Ord a}} -> a -> Bool
|
||||||
|
-- foo a = a == a
|
||||||
|
|
||||||
|
|
||||||
|
flip : ∀ a b c. (a → b → c) → (b → a → c)
|
||||||
|
flip f b a = f a b
|
||||||
|
|
||||||
|
partition : ∀ a. (a → Bool) → List a → List a × List a
|
||||||
|
partition {a} pred xs = go xs Nil Nil
|
||||||
|
where
|
||||||
|
go : List a → List a → List a → List a × List a
|
||||||
|
go Nil as bs = (as, bs)
|
||||||
|
go (x :: xs) as bs = if pred x
|
||||||
|
then go xs (x :: as) bs
|
||||||
|
else go xs as (x :: bs)
|
||||||
|
|
||||||
|
-- probably not super efficient, but it works
|
||||||
|
qsort : ∀ a. (a → a → Bool) → List a → List a
|
||||||
|
qsort lt Nil = Nil
|
||||||
|
qsort lt (x :: xs) = qsort lt (filter (λ y => not $ lt x y) xs) ++ x :: qsort lt (filter (lt x) xs)
|
||||||
|
|
||||||
|
ordNub : ∀ a. {{Eq a}} {{Ord a}} -> List a -> List a
|
||||||
|
ordNub {a} {{ordA}} xs = go $ qsort _<_ xs
|
||||||
|
where
|
||||||
|
go : List a → List a
|
||||||
|
go (a :: b :: xs) = if a == b then go (a :: xs) else a :: go (b :: xs)
|
||||||
|
go t = t
|
||||||
|
|
||||||
|
ite : ∀ a. Bool → a → a → a
|
||||||
|
ite c t e = if c then t else e
|
||||||
|
|||||||
@@ -17,10 +17,6 @@ digits1 (c :: cs) = let x = ord c in
|
|||||||
False => digits1 cs
|
False => digits1 cs
|
||||||
False => digits1 cs
|
False => digits1 cs
|
||||||
|
|
||||||
tail : {a : U} -> List a -> List a
|
|
||||||
tail Nil = Nil
|
|
||||||
tail (x :: xs) = xs
|
|
||||||
|
|
||||||
-- TODO I used @ patterns in Lean
|
-- TODO I used @ patterns in Lean
|
||||||
digits2 : List Char -> List Int
|
digits2 : List Char -> List Int
|
||||||
digits2 xs = case xs of
|
digits2 xs = case xs of
|
||||||
|
|||||||
@@ -96,6 +96,10 @@ solveAutos : Nat -> List MetaEntry -> M ()
|
|||||||
solveAutos mstart [] = pure ()
|
solveAutos mstart [] = pure ()
|
||||||
solveAutos mstart ((Unsolved fc k ctx ty AutoSolve _) :: es) = do
|
solveAutos mstart ((Unsolved fc k ctx ty AutoSolve _) :: es) = do
|
||||||
debug "AUTO solving \{show k} : \{show ty}"
|
debug "AUTO solving \{show k} : \{show ty}"
|
||||||
|
-- fill in solved metas in type
|
||||||
|
x <- quote ctx.lvl ty
|
||||||
|
ty <- eval ctx.env CBN x
|
||||||
|
debug "AUTO ---> \{show ty}"
|
||||||
-- we want the context here too.
|
-- we want the context here too.
|
||||||
top <- get
|
top <- get
|
||||||
[(tm, mc)] <- case !(contextMatches ctx ty) of
|
[(tm, mc)] <- case !(contextMatches ctx ty) of
|
||||||
@@ -138,7 +142,11 @@ logMetas mstart = do
|
|||||||
mc <- readIORef top.metas
|
mc <- readIORef top.metas
|
||||||
let mlen = length mc.metas `minus` mstart
|
let mlen = length mc.metas `minus` mstart
|
||||||
for_ (reverse $ take mlen mc.metas) $ \case
|
for_ (reverse $ take mlen mc.metas) $ \case
|
||||||
(Solved fc k soln) => info fc "solve \{show k} as \{pprint [] !(quote 0 soln)}"
|
(Solved fc k soln) => do
|
||||||
|
-- TODO put a flag on this, vscode is getting overwhelmed and
|
||||||
|
-- dropping errors
|
||||||
|
--info fc "solve \{show k} as \{pprint [] !(quote 0 soln)}"
|
||||||
|
pure ()
|
||||||
(Unsolved fc k ctx ty User cons) => do
|
(Unsolved fc k ctx ty User cons) => do
|
||||||
ty' <- quote ctx.lvl ty
|
ty' <- quote ctx.lvl ty
|
||||||
let names = (toList $ map fst ctx.types)
|
let names = (toList $ map fst ctx.types)
|
||||||
|
|||||||
Reference in New Issue
Block a user