@@ -8,11 +8,13 @@ import Data.Aeson.TH
8import qualified Data.Aeson as A
8import qualified Data.Aeson as A
9import qualified Data.Map as M
9import qualified Data.Map as M
10import qualified Data.Set as S
10import qualified Data.Set as S
11−import Data.Maybe (fromMaybe)
11+import Data.Maybe (fromMaybe, mapMaybe)
12import Data.Text (Text)
12import Data.Text (Text)
13import qualified Data.Text as T
13import qualified Data.Text as T
14import Data.List (nub)
14import Data.List (nub)
15+import Data.Tree (Tree, rootLabel)
15import qualified Data.Graph as G
16import qualified Data.Graph as G
17+import Data.Foldable (toList)
17import Language.PureScript.Crash
19import Language.PureScript.Crash
18import Language.PureScript.Kinds
20import Language.PureScript.Kinds
@@ -57,6 +59,8 @@ data TypeClassData = TypeClassData
57 -- ^ A set of indexes of type argument that are fully determined by other
59 -- ^ A set of indexes of type argument that are fully determined by other
58 -- arguments via functional dependencies. This can be computed from both
60 -- arguments via functional dependencies. This can be computed from both
59 -- typeClassArguments and typeClassDependencies.
61 -- typeClassArguments and typeClassDependencies.
62+ , typeClassCoveringSets :: S.Set (S.Set Int)
63+ -- ^ A sets of arguments that can be used to infer all other arguments.
60 } deriving Show
64 } deriving Show
62-- | A functional dependency indicates a relationship between two sets of
66-- | A functional dependency indicates a relationship between two sets of
@@ -75,8 +79,11 @@ initEnvironment :: Environment
75initEnvironment = Environment M.empty primTypes M.empty M.empty M.empty primClasses primKinds
79initEnvironment = Environment M.empty primTypes M.empty M.empty M.empty primClasses primKinds
78−-- A constructor for TypeClassData that computes which type class arguments are fully determined.
82+-- A constructor for TypeClassData that computes which type class arguments are fully determined
83+-- and argument covering sets.
79-- Fully determined means that this argument cannot be used when selecting a type class instance.
84-- Fully determined means that this argument cannot be used when selecting a type class instance.
85+-- A covering set is a minimal collection of arguments that can be used to find an instance and
86+-- therefore determine all other type arguments.
81-- An example of the difference between determined and fully determined would be with the class:
88-- An example of the difference between determined and fully determined would be with the class:
82-- ```class C a b c | a -> b, b -> a, b -> c```
89-- ```class C a b c | a -> b, b -> a, b -> c```
@@ -84,7 +91,8 @@ initEnvironment = Environment M.empty primTypes M.empty M.empty M.empty primClas
84-- Both `a` and `b` can be used in selecting a type class instance. However, `c` cannot - it is
91-- Both `a` and `b` can be used in selecting a type class instance. However, `c` cannot - it is
85-- fully determined by `a` and `b`.
92-- fully determined by `a` and `b`.
87−-- Define a graph of type class arguments with edges being fundep determiners to determined.
94+-- Define a graph of type class arguments with edges being fundep determiners to determined. Each
95+-- argument also has a self looping edge.
88-- An argument is fully determined if doesn't appear at the start of a path of strongly connected components.
96-- An argument is fully determined if doesn't appear at the start of a path of strongly connected components.
89-- An argument is not fully determined otherwise.
97-- An argument is not fully determined otherwise.
@@ -97,26 +105,51 @@ makeTypeClassData
97 -> [Constraint]
105 -> [Constraint]
98 -> [FunctionalDependency]
106 -> [FunctionalDependency]
99 -> TypeClassData
107 -> TypeClassData
100−makeTypeClassData args m s deps = TypeClassData args m s deps determinedArgs
108+makeTypeClassData args m s deps = TypeClassData args m s deps determinedArgs coveringSets
110+ argumentIndicies = [0 .. length args - 1]
112+ -- each argument determines themselves
113+ identities = (\i -> (i, [i])) <$> argumentIndicies
102 -- list all the edges in the graph: for each fundep an edge exists for each determiner to each determined
115 -- list all the edges in the graph: for each fundep an edge exists for each determiner to each determined
103− contributingDeps = M.fromListWith (++) $ do
116+ contributingDeps = M.fromListWith (++) $ identities ++ do
104 fd <- deps
117 fd <- deps
105 src <- fdDeterminers fd
118 src <- fdDeterminers fd
106 (src, fdDetermined fd) : map (, []) (fdDetermined fd)
119 (src, fdDetermined fd) : map (, []) (fdDetermined fd)
108− -- here we build a graph of which arguments determine other arguments
121+ -- build a graph of which arguments determine other arguments
109− (depGraph, _, fromKey) = G.graphFromEdges ((\(n, v) -> (n, n, nub v)) <$> M.toList contributingDeps)
122+ (depGraph, fromVertex, fromKey) = G.graphFromEdges ((\(n, v) -> (n, n, nub v)) <$> M.toList contributingDeps)
111 -- do there exist any arguments that contribute to `arg` that `arg` doesn't contribute to
124 -- do there exist any arguments that contribute to `arg` that `arg` doesn't contribute to
125+ isFunDepDetermined :: Int -> Bool
112 isFunDepDetermined arg = case fromKey arg of
126 isFunDepDetermined arg = case fromKey arg of
113− Nothing -> False -- not mentioned in fundeps
127+ Nothing -> internalError "Unknown argument index in makeTypeClassData"
114 Just v -> let contributesToVar = G.reachable (G.transposeG depGraph) v
128 Just v -> let contributesToVar = G.reachable (G.transposeG depGraph) v
115 varContributesTo = G.reachable depGraph v
129 varContributesTo = G.reachable depGraph v
116 in any (\r -> not (r `elem` varContributesTo)) contributesToVar
130 in any (\r -> not (r `elem` varContributesTo)) contributesToVar
118 -- find all the arguments that are determined
132 -- find all the arguments that are determined
133+ determinedArgs :: S.Set Int
119− determinedArgs = S.fromList $ filter isFunDepDetermined [0 .. length args - 1]
134+ determinedArgs = S.fromList $ filter isFunDepDetermined argumentIndicies
136+ argFromVertex :: G.Vertex -> Int
137+ argFromVertex index = let (_, arg, _) = fromVertex index in arg
139+ isVertexDetermined :: G.Vertex -> Bool
140+ isVertexDetermined = isFunDepDetermined . argFromVertex
142+ -- from an scc find the non-determined args
143+ sccNonDetermined :: Tree G.Vertex -> Maybe [Int]
144+ sccNonDetermined tree
145+ -- if any arg in an scc is determined then all of them are
146+ | isVertexDetermined (rootLabel tree) = Nothing
147+ | otherwise = Just (argFromVertex <$> toList tree)
149+ -- find the covering sets
150+ coveringSets :: S.Set (S.Set Int)
151+ coveringSets = let funDepSets = sequence (mapMaybe sccNonDetermined (G.scc depGraph))
152+ in S.fromList (S.fromList <$> funDepSets)
122-- The visibility of a name in scope
155-- The visibility of a name in scope