{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ViewPatterns #-}
module Unison.Hashing.V2.ABT (Unison.ABT.Term, hash, hashComponents) where
import Data.List hiding (cycle, find)
import Data.List qualified as List (sort)
import Data.Map qualified as Map
import Data.Set qualified as Set
import Unison.ABT
import Unison.Hash (Hash)
import Unison.Hashing.V2.Tokenizable (Hashable1, hash1)
import Unison.Hashing.V2.Tokenizable qualified as Hashable
import Unison.Prelude
import Prelude hiding (abs, cycle)
hashComponent ::
  forall a f v.
  (Functor f, Hashable1 f, Foldable f, Eq v, Show v, Ord v) =>
  Map.Map v (Term f v a) ->
  (Hash, [(v, Term f v a)])
hashComponent :: forall a (f :: * -> *) v.
(Functor f, Hashable1 f, Foldable f, Eq v, Show v, Ord v) =>
Map v (Term f v a) -> (Hash, [(v, Term f v a)])
hashComponent Map v (Term f v a)
byName =
  let ts :: [(v, Term f v a)]
ts = Map v (Term f v a) -> [(v, Term f v a)]
forall k a. Map k a -> [(k, a)]
Map.toList Map v (Term f v a)
byName
      
      
      ([Hash]
hashes, [Either [v] v]
env) = [Either [v] v] -> [(v, Term f v a)] -> ([Hash], [Either [v] v])
forall a (f :: * -> *) v.
(Eq v, Functor f, Hashable1 f, Show v) =>
[Either [v] v] -> [(v, Term f v a)] -> ([Hash], [Either [v] v])
doHashCycle [] [(v, Term f v a)]
ts
      
      
      commonTokens :: [Hashable.Token]
      commonTokens :: [Token]
commonTokens = Word8 -> Token
Hashable.Tag Word8
1 Token -> [Token] -> [Token]
forall a. a -> [a] -> [a]
: (Hash -> Token) -> [Hash] -> [Token]
forall a b. (a -> b) -> [a] -> [b]
map Hash -> Token
Hashable.Hashed [Hash]
hashes
      
      
      hashName :: v -> Hash
      hashName :: v -> Hash
hashName v
v = [Token] -> Hash
Hashable.accumulate ([Token]
commonTokens [Token] -> [Token] -> [Token]
forall a. [a] -> [a] -> [a]
++ [Hash -> Token
Hashable.Hashed ([Either [v] v] -> Term f v () -> Hash
forall (f :: * -> *) v a.
(Functor f, Hashable1 f, Eq v, Show v) =>
[Either [v] v] -> Term f v a -> Hash
hash' [Either [v] v]
env (v -> Term f v ()
forall v (f :: * -> *). v -> Term f v ()
var v
v :: Term f v ()))])
      ([Hash]
hashes', [(v, Term f v a)]
permutedTerms) =
        [(v, Term f v a)]
ts
          
          [(v, Term f v a)]
-> ([(v, Term f v a)] -> [(Hash, (v, Term f v a))])
-> [(Hash, (v, Term f v a))]
forall a b. a -> (a -> b) -> b
& ((v, Term f v a) -> (Hash, (v, Term f v a)))
-> [(v, Term f v a)] -> [(Hash, (v, Term f v a))]
forall a b. (a -> b) -> [a] -> [b]
map (\(v, Term f v a)
t -> (v -> Hash
hashName ((v, Term f v a) -> v
forall a b. (a, b) -> a
fst (v, Term f v a)
t), (v, Term f v a)
t))
          
          [(Hash, (v, Term f v a))]
-> ([(Hash, (v, Term f v a))] -> [(Hash, (v, Term f v a))])
-> [(Hash, (v, Term f v a))]
forall a b. a -> (a -> b) -> b
& ((Hash, (v, Term f v a)) -> Hash)
-> [(Hash, (v, Term f v a))] -> [(Hash, (v, Term f v a))]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn (Hash, (v, Term f v a)) -> Hash
forall a b. (a, b) -> a
fst
          [(Hash, (v, Term f v a))]
-> ([(Hash, (v, Term f v a))] -> ([Hash], [(v, Term f v a)]))
-> ([Hash], [(v, Term f v a)])
forall a b. a -> (a -> b) -> b
& [(Hash, (v, Term f v a))] -> ([Hash], [(v, Term f v a)])
forall a b. [(a, b)] -> ([a], [b])
unzip
      overallHash :: Hash
overallHash = [Token] -> Hash
Hashable.accumulate ((Hash -> Token) -> [Hash] -> [Token]
forall a b. (a -> b) -> [a] -> [b]
map Hash -> Token
Hashable.Hashed [Hash]
hashes')
   in (Hash
overallHash, [(v, Term f v a)]
permutedTerms)
hashComponents ::
  (Functor f, Hashable1 f, Foldable f, Eq v, Show v, Var v) =>
  (Hash -> Word64 -> Term f v ()) ->
  Map.Map v (Term f v a) ->
  [(Hash, [(v, Term f v a)])]
hashComponents :: forall (f :: * -> *) v a.
(Functor f, Hashable1 f, Foldable f, Eq v, Show v, Var v) =>
(Hash -> Word64 -> Term f v ())
-> Map v (Term f v a) -> [(Hash, [(v, Term f v a)])]
hashComponents Hash -> Word64 -> Term f v ()
termFromHash Map v (Term f v a)
termsByName =
  let bound :: Set v
bound = [v] -> Set v
forall a. Ord a => [a] -> Set a
Set.fromList (Map v (Term f v a) -> [v]
forall k a. Map k a -> [k]
Map.keys Map v (Term f v a)
termsByName)
      escapedVars :: Set v
escapedVars = [Set v] -> Set v
forall (f :: * -> *) a. (Foldable f, Ord a) => f (Set a) -> Set a
Set.unions (Term f v a -> Set v
forall (f :: * -> *) v a. Term f v a -> Set v
freeVars (Term f v a -> Set v) -> [Term f v a] -> [Set v]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Map v (Term f v a) -> [Term f v a]
forall k a. Map k a -> [a]
Map.elems Map v (Term f v a)
termsByName) Set v -> Set v -> Set v
forall a. Ord a => Set a -> Set a -> Set a
`Set.difference` Set v
bound
      sccs :: [[(v, Term f v a)]]
sccs = [(v, Term f v a)] -> [[(v, Term f v a)]]
forall v (f :: * -> *) a.
Var v =>
[(v, Term f v a)] -> [[(v, Term f v a)]]
components (Map v (Term f v a) -> [(v, Term f v a)]
forall k a. Map k a -> [(k, a)]
Map.toList Map v (Term f v a)
termsByName)
      go :: Map v (Term f v ())
-> [[(v, Term f v a)]] -> [(Hash, [(v, Term f v a)])]
go Map v (Term f v ())
_ [] = []
      go Map v (Term f v ())
prevHashes ([(v, Term f v a)]
component : [[(v, Term f v a)]]
rest) =
        let sub :: Term f v a -> Term f v a
sub = [(v, Term f v ())] -> Term f v a -> Term f v a
forall (f :: * -> *) v b a.
(Foldable f, Functor f, Var v) =>
[(v, Term f v b)] -> Term f v a -> Term f v a
substsInheritAnnotation (Map v (Term f v ()) -> [(v, Term f v ())]
forall k a. Map k a -> [(k, a)]
Map.toList Map v (Term f v ())
prevHashes)
            (Hash
h, [(v, Term f v a)]
sortedComponent) = Map v (Term f v a) -> (Hash, [(v, Term f v a)])
forall a (f :: * -> *) v.
(Functor f, Hashable1 f, Foldable f, Eq v, Show v, Ord v) =>
Map v (Term f v a) -> (Hash, [(v, Term f v a)])
hashComponent (Map v (Term f v a) -> (Hash, [(v, Term f v a)]))
-> Map v (Term f v a) -> (Hash, [(v, Term f v a)])
forall a b. (a -> b) -> a -> b
$ [(v, Term f v a)] -> Map v (Term f v a)
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(v
v, Term f v a -> Term f v a
forall {a}. Term f v a -> Term f v a
sub Term f v a
t) | (v
v, Term f v a
t) <- [(v, Term f v a)]
component]
            curHashes :: Map v (Term f v ())
curHashes = [(v, Term f v ())] -> Map v (Term f v ())
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(v
v, Hash -> Word64 -> Term f v ()
termFromHash Hash
h Word64
i) | ((v
v, Term f v a
_), Word64
i) <- [(v, Term f v a)]
sortedComponent [(v, Term f v a)] -> [Word64] -> [((v, Term f v a), Word64)]
forall a b. [a] -> [b] -> [(a, b)]
`zip` [Word64
0 ..]]
            newHashes :: Map v (Term f v ())
newHashes = Map v (Term f v ())
prevHashes Map v (Term f v ()) -> Map v (Term f v ()) -> Map v (Term f v ())
forall k a. Ord k => Map k a -> Map k a -> Map k a
`Map.union` Map v (Term f v ())
curHashes
            newHashesL :: [(v, Term f v ())]
newHashesL = Map v (Term f v ()) -> [(v, Term f v ())]
forall k a. Map k a -> [(k, a)]
Map.toList Map v (Term f v ())
newHashes
            sortedComponent' :: [(v, Term f v a)]
sortedComponent' = [(v
v, [(v, Term f v ())] -> Term f v a -> Term f v a
forall (f :: * -> *) v b a.
(Foldable f, Functor f, Var v) =>
[(v, Term f v b)] -> Term f v a -> Term f v a
substsInheritAnnotation [(v, Term f v ())]
newHashesL Term f v a
t) | (v
v, Term f v a
t) <- [(v, Term f v a)]
sortedComponent]
         in (Hash
h, [(v, Term f v a)]
sortedComponent') (Hash, [(v, Term f v a)])
-> [(Hash, [(v, Term f v a)])] -> [(Hash, [(v, Term f v a)])]
forall a. a -> [a] -> [a]
: Map v (Term f v ())
-> [[(v, Term f v a)]] -> [(Hash, [(v, Term f v a)])]
go Map v (Term f v ())
newHashes [[(v, Term f v a)]]
rest
   in if Set v -> Bool
forall a. Set a -> Bool
Set.null Set v
escapedVars
        then Map v (Term f v ())
-> [[(v, Term f v a)]] -> [(Hash, [(v, Term f v a)])]
forall {a}.
Map v (Term f v ())
-> [[(v, Term f v a)]] -> [(Hash, [(v, Term f v a)])]
go Map v (Term f v ())
forall k a. Map k a
Map.empty [[(v, Term f v a)]]
sccs
        else
          [Char] -> [(Hash, [(v, Term f v a)])]
forall a. HasCallStack => [Char] -> a
error ([Char] -> [(Hash, [(v, Term f v a)])])
-> [Char] -> [(Hash, [(v, Term f v a)])]
forall a b. (a -> b) -> a -> b
$
            [Char]
"can't hashComponents if bindings have free variables:\n  "
              [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [[Char]] -> [Char]
forall a. Show a => a -> [Char]
show ((v -> [Char]) -> [v] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map v -> [Char]
forall a. Show a => a -> [Char]
show (Set v -> [v]
forall a. Set a -> [a]
Set.toList Set v
escapedVars))
              [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"\n  "
              [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [[Char]] -> [Char]
forall a. Show a => a -> [Char]
show ((v -> [Char]) -> [v] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map v -> [Char]
forall a. Show a => a -> [Char]
show (Map v (Term f v a) -> [v]
forall k a. Map k a -> [k]
Map.keys Map v (Term f v a)
termsByName))
hash ::
  forall f v a.
  (Functor f, Hashable1 f, Eq v, Show v) =>
  Term f v a ->
  Hash
hash :: forall (f :: * -> *) v a.
(Functor f, Hashable1 f, Eq v, Show v) =>
Term f v a -> Hash
hash = [Either [v] v] -> Term f v a -> Hash
forall (f :: * -> *) v a.
(Functor f, Hashable1 f, Eq v, Show v) =>
[Either [v] v] -> Term f v a -> Hash
hash' []
hash' ::
  forall f v a.
  (Functor f, Hashable1 f, Eq v, Show v) =>
  [Either [v] v] ->
  Term f v a ->
  Hash
hash' :: forall (f :: * -> *) v a.
(Functor f, Hashable1 f, Eq v, Show v) =>
[Either [v] v] -> Term f v a -> Hash
hash' [Either [v] v]
env = \case
  Var' v
v -> Hash -> (Int -> Hash) -> Maybe Int -> Hash
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Hash
forall {a}. a
die Int -> Hash
hashInt Maybe Int
ind
    where
      lookup :: Either (t v) v -> Bool
lookup (Left t v
cycle) = v
v v -> t v -> Bool
forall a. Eq a => a -> t a -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` t v
cycle
      lookup (Right v
v') = v
v v -> v -> Bool
forall a. Eq a => a -> a -> Bool
== v
v'
      ind :: Maybe Int
ind = (Either [v] v -> Bool) -> [Either [v] v] -> Maybe Int
forall a. (a -> Bool) -> [a] -> Maybe Int
findIndex Either [v] v -> Bool
forall {t :: * -> *}. Foldable t => Either (t v) v -> Bool
lookup [Either [v] v]
env
      hashInt :: Int -> Hash
      hashInt :: Int -> Hash
hashInt Int
i = [Token] -> Hash
Hashable.accumulate [Word64 -> Token
Hashable.Nat (Word64 -> Token) -> Word64 -> Token
forall a b. (a -> b) -> a -> b
$ Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i]
      die :: a
die =
        [Char] -> a
forall a. HasCallStack => [Char] -> a
error ([Char] -> a) -> [Char] -> a
forall a b. (a -> b) -> a -> b
$
          [Char]
"unknown var in environment: "
            [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ v -> [Char]
forall a. Show a => a -> [Char]
show v
v
            [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
" environment = "
            [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Either [v] v] -> [Char]
forall a. Show a => a -> [Char]
show [Either [v] v]
env
  Cycle' [v]
vs f (Term f v a)
t -> ([Term f v a] -> ([Hash], Term f v a -> Hash))
-> (Term f v a -> Hash) -> f (Term f v a) -> Hash
forall a.
([a] -> ([Hash], a -> Hash)) -> (a -> Hash) -> f a -> Hash
forall (f :: * -> *) a.
Hashable1 f =>
([a] -> ([Hash], a -> Hash)) -> (a -> Hash) -> f a -> Hash
hash1 ([v]
-> [Either [v] v] -> [Term f v a] -> ([Hash], Term f v a -> Hash)
hashCycle [v]
vs [Either [v] v]
env) Term f v a -> Hash
forall a. HasCallStack => a
undefined f (Term f v a)
t
  Abs'' v
v Term f v a
t -> [Either [v] v] -> Term f v a -> Hash
forall (f :: * -> *) v a.
(Functor f, Hashable1 f, Eq v, Show v) =>
[Either [v] v] -> Term f v a -> Hash
hash' (v -> Either [v] v
forall a b. b -> Either a b
Right v
v Either [v] v -> [Either [v] v] -> [Either [v] v]
forall a. a -> [a] -> [a]
: [Either [v] v]
env) Term f v a
t
  Tm' f (Term f v a)
t -> ([Term f v a] -> ([Hash], Term f v a -> Hash))
-> (Term f v a -> Hash) -> f (Term f v a) -> Hash
forall a.
([a] -> ([Hash], a -> Hash)) -> (a -> Hash) -> f a -> Hash
forall (f :: * -> *) a.
Hashable1 f =>
([a] -> ([Hash], a -> Hash)) -> (a -> Hash) -> f a -> Hash
hash1 (\[Term f v a]
ts -> ([Hash] -> [Hash]
forall a. Ord a => [a] -> [a]
List.sort ((Term f v a -> Hash) -> [Term f v a] -> [Hash]
forall a b. (a -> b) -> [a] -> [b]
map ([Either [v] v] -> Term f v a -> Hash
forall (f :: * -> *) v a.
(Functor f, Hashable1 f, Eq v, Show v) =>
[Either [v] v] -> Term f v a -> Hash
hash' [Either [v] v]
env) [Term f v a]
ts), [Either [v] v] -> Term f v a -> Hash
forall (f :: * -> *) v a.
(Functor f, Hashable1 f, Eq v, Show v) =>
[Either [v] v] -> Term f v a -> Hash
hash' [Either [v] v]
env)) ([Either [v] v] -> Term f v a -> Hash
forall (f :: * -> *) v a.
(Functor f, Hashable1 f, Eq v, Show v) =>
[Either [v] v] -> Term f v a -> Hash
hash' [Either [v] v]
env) f (Term f v a)
t
  where
    hashCycle :: [v] -> [Either [v] v] -> [Term f v a] -> ([Hash], Term f v a -> Hash)
    hashCycle :: [v]
-> [Either [v] v] -> [Term f v a] -> ([Hash], Term f v a -> Hash)
hashCycle [v]
cycle [Either [v] v]
env [Term f v a]
ts =
      let ([Hash]
ts', [Either [v] v]
env') = [Either [v] v] -> [(v, Term f v a)] -> ([Hash], [Either [v] v])
forall a (f :: * -> *) v.
(Eq v, Functor f, Hashable1 f, Show v) =>
[Either [v] v] -> [(v, Term f v a)] -> ([Hash], [Either [v] v])
doHashCycle [Either [v] v]
env ([v] -> [Term f v a] -> [(v, Term f v a)]
forall a b. [a] -> [b] -> [(a, b)]
zip [v]
cycle [Term f v a]
ts)
       in ([Hash]
ts', [Either [v] v] -> Term f v a -> Hash
forall (f :: * -> *) v a.
(Functor f, Hashable1 f, Eq v, Show v) =>
[Either [v] v] -> Term f v a -> Hash
hash' [Either [v] v]
env')
doHashCycle ::
  forall a f v.
  (Eq v, Functor f, Hashable1 f, Show v) =>
  [Either [v] v] ->
  [(v, Term f v a)] ->
  ([Hash], [Either [v] v])
doHashCycle :: forall a (f :: * -> *) v.
(Eq v, Functor f, Hashable1 f, Show v) =>
[Either [v] v] -> [(v, Term f v a)] -> ([Hash], [Either [v] v])
doHashCycle [Either [v] v]
env [(v, Term f v a)]
namedTerms =
  ((Term f v a -> Hash) -> [Term f v a] -> [Hash]
forall a b. (a -> b) -> [a] -> [b]
map ([Either [v] v] -> Term f v a -> Hash
forall (f :: * -> *) v a.
(Functor f, Hashable1 f, Eq v, Show v) =>
[Either [v] v] -> Term f v a -> Hash
hash' [Either [v] v]
newEnv) [Term f v a]
permutedTerms, [Either [v] v]
newEnv)
  where
    names :: [v]
names = ((v, Term f v a) -> v) -> [(v, Term f v a)] -> [v]
forall a b. (a -> b) -> [a] -> [b]
map (v, Term f v a) -> v
forall a b. (a, b) -> a
fst [(v, Term f v a)]
namedTerms
    
    permutationEnv :: [Either [v] v]
permutationEnv = [v] -> Either [v] v
forall a b. a -> Either a b
Left [v]
names Either [v] v -> [Either [v] v] -> [Either [v] v]
forall a. a -> [a] -> [a]
: [Either [v] v]
env
    ([v]
permutedNames, [Term f v a]
permutedTerms) =
      [(v, Term f v a)]
namedTerms
        [(v, Term f v a)]
-> ([(v, Term f v a)] -> [(v, Term f v a)]) -> [(v, Term f v a)]
forall a b. a -> (a -> b) -> b
& ((v, Term f v a) -> Hash) -> [(v, Term f v a)] -> [(v, Term f v a)]
forall b a. Ord b => (a -> b) -> [a] -> [a]
sortOn ([Either [v] v] -> Term f v a -> Hash
forall (f :: * -> *) v a.
(Functor f, Hashable1 f, Eq v, Show v) =>
[Either [v] v] -> Term f v a -> Hash
hash' [Either [v] v]
permutationEnv (Term f v a -> Hash)
-> ((v, Term f v a) -> Term f v a) -> (v, Term f v a) -> Hash
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (v, Term f v a) -> Term f v a
forall a b. (a, b) -> b
snd)
        [(v, Term f v a)]
-> ([(v, Term f v a)] -> ([v], [Term f v a]))
-> ([v], [Term f v a])
forall a b. a -> (a -> b) -> b
& [(v, Term f v a)] -> ([v], [Term f v a])
forall a b. [(a, b)] -> ([a], [b])
unzip
    
    
    newEnv :: [Either [v] v]
newEnv = (v -> Either [v] v) -> [v] -> [Either [v] v]
forall a b. (a -> b) -> [a] -> [b]
map v -> Either [v] v
forall a b. b -> Either a b
Right [v]
permutedNames [Either [v] v] -> [Either [v] v] -> [Either [v] v]
forall a. [a] -> [a] -> [a]
++ [Either [v] v]
env