wip factoring out logic for hashing strongly connected components

This commit is contained in:
Paul Chiusano 2018-10-23 17:38:58 -04:00
parent ac5f973efc
commit 2c678a6918
6 changed files with 58 additions and 50 deletions

View File

@ -32,6 +32,7 @@ import qualified Data.Text as Text
import qualified Data.Vector as Vector
import qualified Unison.Hashable as Hashable
import qualified Unison.Var as Var
import qualified Unison.Util.Components as Components
data ABT f v r
= Var v
@ -452,6 +453,9 @@ instance (Foldable f, Functor f, Eq1 f, Var v) => Eq (Term f v a) where
go (Tm f1) (Tm f2) = f1 ==# f2
go _ _ = False
components :: Var v => [(v, Term f v a)] -> [[(v, Term f v a)]]
components = Components.components freeVars
-- Hash a strongly connected component and sort its definitions into a canonical order.
hashComponent ::
(Functor f, Hashable1 f, Foldable f, Eq v, Var v, Ord h, Accumulate h)

View File

@ -19,7 +19,6 @@ import Unison.Reference (Reference)
import qualified Unison.Reference as Reference
import Unison.Type (AnnotatedType)
import qualified Unison.Type as Type
import Unison.Typechecker.Components (components)
import Unison.Var (Var)
type DataDeclaration v = DataDeclaration' v ()
@ -138,7 +137,7 @@ hashDecls0
:: (Eq v, Var v)
=> Map v (DataDeclaration' v ())
-> [(v, Reference, DataDeclaration' v ())]
hashDecls0 decls = reverse . snd . foldl f ([], []) $ components abts
hashDecls0 decls = reverse . snd . foldl f ([], []) $ ABT.components abts
where
f (m, newDecls) cycle =
let

View File

@ -7,6 +7,8 @@ import Unison.Hashable as Hashable
import qualified Data.Text as Text
import qualified Unison.Hash as H
-- could add a `Word` parameter to `Derived`
-- associated with each hash would actually be a list of terms / type decls
data Reference = Builtin Text.Text | Derived H.Hash deriving (Eq,Ord,Generic)
instance Show Reference where

View File

@ -1,65 +1,19 @@
module Unison.Typechecker.Components (components, minimize, minimize') where
module Unison.Typechecker.Components (minimize, minimize') where
import Control.Arrow ((&&&))
import Data.Bifunctor (first)
import Data.Function (on)
import qualified Data.Graph as Graph
import Data.List (groupBy, sortBy)
import Data.List.NonEmpty (NonEmpty)
import qualified Data.List.NonEmpty as Nel
import qualified Data.Map as Map
import Data.Maybe
import Data.Set (Set)
import qualified Data.Set as Set
import qualified Unison.ABT as ABT
import Unison.Term (AnnotatedTerm')
import qualified Unison.Term as Term
import Unison.Var (Var)
components
:: Var v => [(v, ABT.Term f v a)] -> [[(v, ABT.Term f v a)]]
components = components' ABT.freeVars
-- | Order bindings by dependencies and group into components.
-- Each component consists of > 1 bindings, each of which depends
-- transitively on all other bindings in the component.
--
-- 1-element components may or may not depend on themselves.
--
-- The order is such that a component at index i will not depend
-- on components and indexes > i. But a component at index i does not
-- _necessarily_ depend on any components at earlier indices.
--
-- Example:
--
-- let rec
-- ping n = pong (n + 1);
-- pong n = ping (n + 1);
-- g = id 42;
-- y = id "hi"
-- id x = x;
-- in ping g
--
-- `components` would produce `[[ping,pong], [id], [g], [y]]`
-- Notice that `id` comes before `g` and `y` in the output, since
-- both `g` and `y` depend on `id`.
--
-- Uses Tarjan's algorithm:
-- https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
components' :: Var v => (t -> Set v) -> [(v, t)] -> [[(v, t)]]
components' freeVars bs =
let varIds =
Map.fromList (map fst bs `zip` reverse [(1 :: Int) .. length bs])
-- something horribly wrong if this bombs
varId v = fromJust $ Map.lookup v varIds
-- use ints as keys for graph to preserve original source order as much as
-- possible
graph = [ ((v, b), varId v, deps b) | (v, b) <- bs ]
vars = Set.fromList (map fst bs)
deps b = varId <$> Set.toList (Set.intersection vars (freeVars b))
in Graph.flattenSCC <$> Graph.stronglyConnComp graph
-- | Algorithm for minimizing cycles of a `let rec`. This can
-- improve generalization during typechecking and may also be more
-- efficient for execution.
@ -87,7 +41,7 @@ minimize (Term.LetRecNamedAnnotatedTop' isTop ann bs e) =
in if not $ null dupes
then Left $ Nel.fromList dupes
else
let cs = components bindings
let cs = ABT.components bindings
varAnnotations = Map.fromList ((\((a, v), _) -> (v, a)) <$> bs)
annotationFor v = fromJust $ Map.lookup v varAnnotations
annotatedVar v = (annotationFor v, v)

View File

@ -0,0 +1,48 @@
module Unison.Util.Components where
import qualified Data.Graph as Graph
import qualified Data.Map as Map
import Data.Maybe
import Data.Set (Set)
import qualified Data.Set as Set
import Unison.Var (Var)
-- | Order bindings by dependencies and group into components.
-- Each component consists of > 1 bindings, each of which depends
-- transitively on all other bindings in the component.
--
-- 1-element components may or may not depend on themselves.
--
-- The order is such that a component at index i will not depend
-- on components and indexes > i. But a component at index i does not
-- _necessarily_ depend on any components at earlier indices.
--
-- Example:
--
-- let rec
-- ping n = pong (n + 1);
-- pong n = ping (n + 1);
-- g = id 42;
-- y = id "hi"
-- id x = x;
-- in ping g
--
-- `components` would produce `[[ping,pong], [id], [g], [y]]`
-- Notice that `id` comes before `g` and `y` in the output, since
-- both `g` and `y` depend on `id`.
--
-- Uses Tarjan's algorithm:
-- https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
components :: Var v => (t -> Set v) -> [(v, t)] -> [[(v, t)]]
components freeVars bs =
let varIds =
Map.fromList (map fst bs `zip` reverse [(1 :: Int) .. length bs])
-- something horribly wrong if this bombs
varId v = fromJust $ Map.lookup v varIds
-- use ints as keys for graph to preserve original source order as much as
-- possible
graph = [ ((v, b), varId v, deps b) | (v, b) <- bs ]
vars = Set.fromList (map fst bs)
deps b = varId <$> Set.toList (Set.intersection vars (freeVars b))
in Graph.flattenSCC <$> Graph.stronglyConnComp graph

View File

@ -87,6 +87,7 @@ library
Unison.UnisonFile
Unison.Util.AnnotatedText
Unison.Util.ColorText
Unison.Util.Components
Unison.Util.Logger
Unison.Util.Menu
Unison.Util.Monoid