Skip to content

Commit 1dcc332

Browse files
committed
Move recursion schemes to separate package
1 parent b422a7d commit 1dcc332

25 files changed

Lines changed: 223 additions & 82 deletions

File tree

codebase2/codebase/U/Codebase/Decl.hs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import U.Core.ABT qualified as ABT
1212
import U.Core.ABT.Var qualified as ABT
1313
import Unison.Hash (Hash)
1414
import Unison.Prelude
15+
import Unison.Util.Recursion
1516

1617
type ConstructorId = Word64
1718

@@ -107,7 +108,7 @@ unhashComponent componentHash refToVar m =
107108
{ declType,
108109
modifier,
109110
bound,
110-
constructorTypes = ABT.cata alg <$> constructorTypes
111+
constructorTypes = cata alg <$> constructorTypes
111112
}
112113
where
113114
rewriteTypeReference :: Reference.Id' (Maybe Hash) -> Either v Reference.Reference
@@ -126,8 +127,8 @@ unhashComponent componentHash refToVar m =
126127
case Map.lookup (fromMaybe componentHash <$> rid) withGeneratedVars of
127128
Nothing -> error "unhashComponent: self-reference not found in component map"
128129
Just (v, _, _) -> Left v
129-
alg :: () -> ABT.ABT (Type.F' TypeRef) v (HashableType v) -> HashableType v
130-
alg () = \case
130+
alg :: ABT.Term' (Type.F' TypeRef) v () (HashableType v) -> HashableType v
131+
alg (ABT.Term' _ () abt) = case abt of
131132
ABT.Var v -> ABT.var () v
132133
ABT.Cycle body -> ABT.cycle () body
133134
ABT.Abs v body -> ABT.abs () v body

codebase2/codebase/U/Codebase/Term.hs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import U.Core.ABT qualified as ABT
1616
import U.Core.ABT.Var qualified as ABT
1717
import Unison.Hash (Hash)
1818
import Unison.Prelude
19+
import Unison.Util.Recursion
1920

2021
type ConstructorId = Word64
2122

@@ -281,7 +282,7 @@ unhashComponent componentHash refToVar m =
281282
assignVar :: Reference.Id -> (trm, extra) -> StateT (Set v) Identity (v, trm, extra)
282283
assignVar r (trm, extra) = (,trm,extra) <$> ABT.freshenS (refToVar r)
283284
fillSelfReferences :: Term v -> HashableTerm v
284-
fillSelfReferences = (ABT.cata alg)
285+
fillSelfReferences = cata alg
285286
where
286287
rewriteTermReference :: Reference.Id' (Maybe Hash) -> Either v Reference.Reference
287288
rewriteTermReference rid@(Reference.Id mayH pos) =
@@ -299,8 +300,8 @@ unhashComponent componentHash refToVar m =
299300
case Map.lookup (fromMaybe componentHash <$> rid) withGeneratedVars of
300301
Nothing -> error "unhashComponent: self-reference not found in component map"
301302
Just (v, _, _) -> Left v
302-
alg :: () -> ABT.ABT (F v) v (HashableTerm v) -> HashableTerm v
303-
alg () = \case
303+
alg :: ABT.Term' (F v) v () (HashableTerm v) -> HashableTerm v
304+
alg (ABT.Term' _ () abt) = case abt of
304305
ABT.Var v -> ABT.var () v
305306
ABT.Cycle body -> ABT.cycle () body
306307
ABT.Abs v body -> ABT.abs () v body

codebase2/codebase/package.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ dependencies:
1111
- unison-core
1212
- unison-hash
1313
- unison-prelude
14+
- unison-util-recursion
1415

1516
library:
1617
source-dirs: .

codebase2/codebase/unison-codebase.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,5 @@ library
6969
, unison-core
7070
, unison-hash
7171
, unison-prelude
72+
, unison-util-recursion
7273
default-language: GHC2021

codebase2/core/U/Core/ABT.hs

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import Debug.RecoverRTTI qualified as RTTI
1010
import U.Core.ABT.Var (Var (freshIn))
1111
import Unison.Debug qualified as Debug
1212
import Unison.Prelude
13+
import Unison.Util.Recursion
1314
import Prelude hiding (abs, cycle)
1415

1516
data ABT f v r
@@ -24,6 +25,13 @@ data ABT f v r
2425
data Term f v a = Term {freeVars :: Set v, annotation :: a, out :: ABT f v (Term f v a)}
2526
deriving (Functor, Foldable, Generic, Traversable)
2627

28+
data Term' f v a x = Term' {freeVars' :: Set v, annotation' :: a, out' :: ABT f v x}
29+
deriving (Functor)
30+
31+
instance (Functor f) => Recursive (Term f v a) (Term' f v a) where
32+
embed (Term' vs a abt) = Term vs a abt
33+
project (Term vs a abt) = Term' vs a abt
34+
2735
instance (Foldable f, Functor f, forall a. (Eq a) => Eq (f a), Var v) => Eq (Term f v a) where
2836
-- alpha equivalence, works by renaming any aligned Abs ctors to use a common fresh variable
2937
t1 == t2 = go (out t1) (out t2)
@@ -97,24 +105,6 @@ vmapM f (Term _ a out) = case out of
97105
Cycle r -> cycle a <$> vmapM f r
98106
Abs v body -> abs a <$> f v <*> vmapM f body
99107

100-
cata ::
101-
(Functor f) =>
102-
(a -> ABT f v x -> x) ->
103-
Term f v a ->
104-
x
105-
cata abtAlg =
106-
let go (Term _fvs a out) = abtAlg a (fmap go out)
107-
in go
108-
109-
para ::
110-
(Functor f) =>
111-
(a -> ABT f v (Term f v a, x) -> x) ->
112-
Term f v a ->
113-
x
114-
para abtAlg =
115-
let go (Term _fvs a out) = abtAlg a (fmap (\x -> (x, go x)) out)
116-
in go
117-
118108
transform ::
119109
(Ord v, Foldable g, Functor g) =>
120110
(forall a. f a -> g a) ->

codebase2/core/package.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ dependencies:
1717
- text
1818
- unison-hash
1919
- unison-prelude
20+
- unison-util-recursion
2021

2122
default-extensions:
2223
- ApplicativeDo

codebase2/core/unison-core.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,5 @@ library
6464
, text
6565
, unison-hash
6666
, unison-prelude
67+
, unison-util-recursion
6768
default-language: Haskell2010

contrib/cabal.project

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ packages:
2121
lib/unison-util-base32hex
2222
lib/unison-util-bytes
2323
lib/unison-util-cache
24+
lib/unison-util-file-embed
25+
lib/unison-util-recursion
2426
lib/unison-util-relation
2527
lib/unison-util-rope
26-
lib/unison-util-file-embed
2728

2829
parser-typechecker
2930
unison-core
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: unison-util-recursion
2+
github: unisonweb/unison
3+
copyright: Copyright (C) 2013-2022 Unison Computing, PBC and contributors
4+
5+
ghc-options: -Wall
6+
7+
dependencies:
8+
- base
9+
- free
10+
11+
library:
12+
source-dirs: src
13+
when:
14+
- condition: false
15+
other-modules: Paths_unison_util_recursion
16+
17+
default-extensions:
18+
- ApplicativeDo
19+
- BangPatterns
20+
- BlockArguments
21+
- DeriveAnyClass
22+
- DeriveFoldable
23+
- DeriveFunctor
24+
- DeriveGeneric
25+
- DeriveTraversable
26+
- DerivingStrategies
27+
- DerivingVia
28+
- DoAndIfThenElse
29+
- DuplicateRecordFields
30+
- FlexibleContexts
31+
- FlexibleInstances
32+
- FunctionalDependencies
33+
- GeneralizedNewtypeDeriving
34+
- ImportQualifiedPost
35+
- LambdaCase
36+
- MultiParamTypeClasses
37+
- NamedFieldPuns
38+
- OverloadedStrings
39+
- PatternSynonyms
40+
- RankNTypes
41+
- ScopedTypeVariables
42+
- StandaloneDeriving
43+
- TupleSections
44+
- TypeApplications
45+
- TypeFamilies
46+
- ViewPatterns
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{-# LANGUAGE DefaultSignatures #-}
2+
{-# LANGUAGE QuantifiedConstraints #-}
3+
{-# LANGUAGE UndecidableInstances #-}
4+
5+
module Unison.Util.Recursion
6+
( Algebra,
7+
Recursive (..),
8+
cataM,
9+
para,
10+
Fix (..),
11+
Cofree' (..),
12+
)
13+
where
14+
15+
import Control.Arrow ((&&&))
16+
import Control.Comonad.Cofree (Cofree ((:<)))
17+
import Control.Monad ((<=<))
18+
19+
type Algebra f a = f a -> a
20+
21+
class Recursive t f | t -> f where
22+
cata :: (Algebra f a) -> t -> a
23+
default cata :: (Functor f) => (f a -> a) -> t -> a
24+
cata φ = φ . fmap (cata φ) . project
25+
project :: t -> f t
26+
default project :: (Functor f) => t -> f t
27+
project = cata (fmap embed)
28+
embed :: f t -> t
29+
{-# MINIMAL embed, (cata | project) #-}
30+
31+
cataM :: (Recursive t f, Traversable f, Monad m) => (f a -> m a) -> t -> m a
32+
cataM φ = cata $ φ <=< sequenceA
33+
34+
para :: (Recursive t f, Functor f) => (f (t, a) -> a) -> t -> a
35+
para φ = snd . cata (embed . fmap fst &&& φ)
36+
37+
newtype Fix f = Fix (f (Fix f))
38+
39+
deriving instance (forall a. (Show a) => Show (f a)) => Show (Fix f)
40+
41+
deriving instance (forall a. (Eq a) => Eq (f a)) => Eq (Fix f)
42+
43+
deriving instance (Eq (Fix f), forall a. (Ord a) => Ord (f a)) => Ord (Fix f)
44+
45+
instance (Functor f) => Recursive (Fix f) f where
46+
embed = Fix
47+
project (Fix f) = f
48+
49+
data Cofree' f a x = a :<< f x
50+
deriving (Foldable, Functor, Traversable)
51+
52+
-- |
53+
--
54+
-- __NB__: `Cofree` from “free” is lazy, so this instance is technically partial.
55+
instance (Functor f) => Recursive (Cofree f a) (Cofree' f a) where
56+
embed (a :<< fco) = a :< fco
57+
project (a :< fco) = a :<< fco

0 commit comments

Comments
 (0)