Kris Nuttycombe (@nuttycom) - January, 2018
data Task = Task
{ title :: Text
, description :: Text
, dependsOn :: [Task]
, state :: TaskState
, tags :: Set TaskTag
, estimate :: Int
}
data Task = Task
{ title :: Text
, description :: Text
, dependsOn :: [Task]
, state :: TaskState
, tags :: Set TaskTag
, estimate :: Int
}
taskCost :: Task -> Int
data Task = Task
{ title :: Text
, description :: Text
, dependsOn :: [Task]
, state :: TaskState
, tags :: Set TaskTag
, estimate :: Int
}
taskCost :: Task -> Int
taskCost task =
estimate task + sum (fmap taskCost (dependsOn task))
taskCost :: Task -> Int
taskCost task = length $ dependsOn task
data Task n = Task
{ title :: Text
, description :: Text
, dependsOn :: [Task n]
, state :: TaskState
, tags :: Set TaskTag
, estimate :: n
}
taskCost :: (Monoid n) => Task n -> n
taskCost task =
estimate task <> foldMap taskCost (dependsOn task)
taskCost :: (Monoid n) => Task -> n
taskCost = const mempty
data Task n = Task
{ title :: Text
, description :: Text
, dependsOn :: [Task n]
, state :: TaskState
, tags :: Set TaskTag
, estimate :: n
}
taskCost :: (Semigroup n) => Task n -> n
taskCost task =
sconcat (estimate task :| fmap taskCost (dependsOn task))
data Task n = Task
{ title :: Text
, description :: Text
, dependsOn :: [Task n]
, state :: TaskState
, tags :: Set TaskTag
, estimate :: n
}
newtype TaskStore n = TaskStore { unTaskStore :: Map TaskRef (TaskF n) }
findTask :: TaskStore n
-> TaskRef
-> Maybe (Task n)
data Task n = Task
{ title :: Text
, description :: Text
, dependsOn :: [TaskRef]
, state :: TaskState
, tags :: Set TaskTag
, estimate :: n
}
newtype TaskStore n = TaskStore { unTaskStore :: Map TaskRef (TaskF n) }
findTask :: TaskStore n
-> TaskRef
-> Maybe (Task n)
data TaskF n a = TaskF
{ title :: Text
, description :: Text
, dependsOn :: [a]
, state :: TaskState
, tags :: Set TaskTag
, estimate :: n
}
newtype TaskStore n a = TaskStore { unTaskStore :: Map a (TaskF n a) }
findTaskF :: (Ord a)
=> TaskStore n a
-> a
-> Maybe (TaskF n a)
data TaskF n a = TaskF
{ title :: Text
, description :: Text
, dependsOn :: [a]
, state :: TaskState
, tags :: Set TaskTag
, estimate :: n
}
newtype TaskStore n a = TaskStore { unTaskStore :: Map a (TaskF n a) }
findTaskF :: (Ord a)
=> TaskStore n a
-> a
-> Maybe (TaskF n a)
findTaskF = flip lookup . unTaskStore
/Users/nuttycom/personal/lc_winter-2018-tdd/src/Task2.hs:29:44: error:
• Couldn't match type ‘a’ with ‘TaskF n a0’
‘a’ is a rigid type variable bound by
the type signature for:
taskCost :: forall n a. Semigroup n => TaskF n a -> n
at src/Task2.hs:27:1-43
Expected type: [TaskF n a0]
Actual type: [a]
• In the second argument of ‘fmap’, namely ‘(dependsOn task)’
In the second argument of ‘(:|)’, namely
‘fmap taskCost (dependsOn task)’
In the first argument of ‘sconcat’, namely
‘(estimate task :| fmap taskCost (dependsOn task))’
• Relevant bindings include
task :: TaskF n a (bound at src/Task2.hs:28:10)
taskCost :: TaskF n a -> n (bound at src/Task2.hs:28:1)
|
29 | sconcat (estimate task :| fmap taskCost (dependsOn task))
| ^^^^^^^^^^^^^^
taskCost :: (Semigroup n) => Task n -> n
taskCost task =
sconcat (estimate task :| fmap taskCost (dependsOn task))
findTaskF :: (Ord a)
=> TaskStore n a
-> a
-> Maybe (TaskF n a)
taskCost :: (Semigroup n, Ord a)
=> TaskStore n a
-> TaskF n a
-> n
taskCost :: (Semigroup n) => Task n -> n
taskCost task =
sconcat (estimate task :| fmap taskCost (dependsOn task))
findTaskF :: (Ord a)
=> TaskStore n a
-> a
-> Maybe (TaskF n a)
taskCost :: (Semigroup n, Ord a)
=> TaskStore n a
-> TaskF n a
-> n
taskCost s task =
let deps = catMaybes . fmap (findTaskF s) $ dependsOn task
in sconcat (estimate task :| fmap (taskCost s) deps)
data TaskF n a = TaskF
{ title :: Text
, description :: Text
, dependsOn :: [a]
, state :: TaskState
, tags :: Set TaskTag
, estimate :: n
} deriving Functor
-- from Data.Functor.Foldable
newtype Fix (f :: * -> *) = Fix { unfix :: f (Fix f) }
type Task n = Fix (TaskF n)
findTask :: (Ord a)
=> TaskStore n a
-> a
-> Either (NonEmpty a) (Task n)
type Task n = Fix (TaskF n)
findTaskF :: (Ord a)
=> TaskStore n a
-> a
-> Maybe (TaskF n a)
findTask :: (Ord a)
=> TaskStore n a
-> a
-> Either (NonEmpty a) (Task n)
findTask store ref =
type Task n = Fix (TaskF n)
findTaskF :: (Ord a)
=> TaskStore n a
-> a
-> Maybe (TaskF n a)
import Data.Semigroup (:|)
findTask :: (Ord a)
=> TaskStore n a
-> a
-> Either (NonEmpty a) (Task n)
findTask s ref = do
root <- maybe (Left $ ref :| []) Right (findTaskF store ref)
type Task n = Fix (TaskF n)
findTaskF :: (Ord a)
=> TaskStore n a
-> a
-> Maybe (TaskF n a)
import Data.Semigroup (:|)
import Data.Validation as V
findTask :: (Ord a)
=> TaskStore n a
-> a
-> Either (NonEmpty a) (Task n)
findTask s ref = do
root <- maybe (Left $ ref :| []) Right (findTaskF s ref)
root' <- V.toEither $ traverse (V.fromEither . findTask s) root
type Task n = Fix (TaskF n)
findTaskF :: (Ord a)
=> TaskStore n a
-> a
-> Maybe (TaskF n a)
import Data.Semigroup (:|)
import Data.Validation as V
findTask :: (Ord a)
=> TaskStore n a
-> a
-> Either (NonEmpty a) (Task n)
findTask s ref = do
root <- maybe (Left $ ref :| []) Right (findTaskF s ref)
root' <- V.toEither $ traverse (V.fromEither . findTask s) root
pure $ embed root
type Task n = Fix (TaskF n)
findTaskF :: (Ord a)
=> TaskStore n a
-> a
-> Maybe (TaskF n a)
taskCost :: (Semigroup n) => Task n -> n
taskCost = cata (\t -> sconcat (estimate t :| dependsOn t))
graph :: (Ord a, Show a) => TaskStore n a -> a -> DotGraph a
graph s a =
let nodes = a : transitiveDeps s a
edges' (a, tf) = (a,,()) <$> dependsOn tf
edges = edges' =<< (\a' -> fmap (a',) . F.toList $ findTaskF s a') =<< nodes
in graphElemsToDot (graphParams s) ((,()) <$> nodes) (L.nub edges)
graphParams :: (Ord a) => TaskStore n a -> GraphvizParams a al el () al
graphParams s = nonClusteredParams
{ isDirected = True
, globalAttributes =
[ GraphAttrs [RankDir FromLeft]
, NodeAttrs [shape DoubleCircle]
]
, fmtNode = \(a, _) ->
let attrs t = toLabel (title t) : taskStyle (taskState t)
in maybe [] attrs $ findTaskF s a
}
taskStyle :: TaskState -> [Attribute]
taskStyle (Created Task) = []
taskStyle (Created Bug) = [style filled, fillColor Tomato]
taskStyle Completed = [style filled, fillColor LawnGreen]
"Bug fixing strategy: forbid yourself to fix the bug. Instead, render the bug impossible by construction." --Paul Phillips
How many different values can this function possibly return?
f :: () -> Bool
How many different values can this function possibly return?
f :: () -> Bool -- 2 possible values
g :: () -> Int32
How many different values can this function possibly return?
f :: () -> Bool -- 2 possible values
g :: () -> Int32 -- 2^32 possible values
k :: () -> Either Bool Int32
How many different values can this function possibly return?
f :: () -> Bool -- 2 possible values
g :: () -> Int32 -- 2^32 possible values
k :: () -> Either Bool Int32 -- 2 + 2^32 possible values
h :: () -> (Bool, Int32)
How many different values can this function possibly return?
f :: () -> Bool -- 2 possible values
g :: () -> Int32 -- 2^32 possible values
k :: () -> Either Bool Int32 -- 2 + 2^32 possible values
h :: () -> (Bool, Int32) -- 2 * 2^32 = 2^33 possible values
h :: () -> Either Int32 Int32 -- 2^32 + 2^32 = 2^33 possible values
k :: () -> Text
How many different values can this function possibly return?
f :: () -> Bool -- 2 possible values
g :: () -> Int32 -- 2^32 possible values
k :: () -> Either Bool Int32 -- 2 + 2^32 possible values
h :: () -> (Bool, Int32) -- 2 * 2^32 = 2^33 possible values
h :: () -> Either Int32 Int32 -- 2^32 + 2^32 = 2^33 possible values
k :: () -> Text -- 😬😖😩😷
insertTaskF :: (Ord a)
=> TaskStore n a
-> a
-> TaskF n a
-> Either (NonEmpty a) (TaskStore n a)
type T a b = forall c. (a -> b -> c) -> c
type E a b = forall c. (a -> c) -> (b -> c) -> c
How many different values can these functions possibly return?
f :: () -> T Bool Int32
g :: () -> E Bool Int32
type T a b = forall c. (a -> b -> c) -> c
type E a b = forall c. (a -> c) -> (b -> c) -> c
How many different values can these functions possibly return?
f :: () -> T Bool Int32 -- 2 * 2^32 = 2^33 possible values!
g :: () -> E Bool Int32 -- 2 + 2^32 possible values!