mirror of
https://github.com/github/semantic.git
synced 2024-12-25 07:55:12 +03:00
Merge branch 'master' into output-typeclass
This commit is contained in:
commit
e53adbd247
@ -79,9 +79,6 @@ library
|
||||
, Syntax
|
||||
, Term
|
||||
, TreeSitter
|
||||
, FDoc.Term
|
||||
, FDoc.RecursionSchemes
|
||||
, FDoc.NatExample
|
||||
build-depends: base >= 4.8 && < 5
|
||||
, aeson
|
||||
, ansi-terminal
|
||||
|
@ -1,60 +0,0 @@
|
||||
module FDoc.NatExample where
|
||||
|
||||
import Prologue
|
||||
import Data.Functor.Foldable
|
||||
|
||||
-- Our base Functor. The recursive bit is parameterized by r.
|
||||
data NatF r =
|
||||
ZeroF
|
||||
| SuccF r
|
||||
deriving (Show, Functor)
|
||||
|
||||
-- Fix represents the "fixed point" for the NatF Functor, and enables recursion.
|
||||
-- Important to note this has kind * -> *.
|
||||
type Nat = Fix NatF
|
||||
|
||||
-- This is a fully applied type (Has kind *).
|
||||
zero' :: Nat
|
||||
zero' = Fix ZeroF
|
||||
|
||||
-- This is a partially applied type (has kind * -> *). The recursive bit is used
|
||||
-- by recursion schemes and is referred to as the "carrier" functor.
|
||||
succ' :: Nat -> Nat
|
||||
succ' = Fix . SuccF
|
||||
|
||||
-- Catamorphism: "tear down" a recursive structure in the shape of Nat.
|
||||
natToIntCata :: Nat -> Int
|
||||
natToIntCata nats = cata algebra nats
|
||||
where
|
||||
algebra term = case term of
|
||||
ZeroF -> 0
|
||||
SuccF value -> 1 + value
|
||||
|
||||
-- Anamorphism: "build up" a recursive structure in the shape of Nat.
|
||||
intToNatAna :: Int -> Nat
|
||||
intToNatAna num = ana coalgebra num
|
||||
where
|
||||
coalgebra num = case num of
|
||||
0 -> ZeroF
|
||||
_ -> SuccF (num - 1)
|
||||
|
||||
-- Hylomorphism: first apply an anamorphism and then a catamorphism in the shape
|
||||
-- of Nat.
|
||||
natHylo :: Int -> Int
|
||||
natHylo num = hylo algebra coalgebra num
|
||||
where
|
||||
algebra term = case term of
|
||||
ZeroF -> 0
|
||||
SuccF value -> 1 + value
|
||||
coalgebra num = case num of
|
||||
0 -> ZeroF
|
||||
_ -> SuccF (num - 1)
|
||||
|
||||
-- Paramorphism: primitive recursion maintaining the original value along with
|
||||
-- its computed value.
|
||||
natPara :: Nat -> Int
|
||||
natPara nats = para algebra nats
|
||||
where
|
||||
algebra value = case value of
|
||||
ZeroF -> 0
|
||||
(SuccF (_, value')) -> 1 + value'
|
@ -1,186 +0,0 @@
|
||||
{-# LANGUAGE DataKinds, ScopedTypeVariables, TypeFamilies, TypeOperators #-}
|
||||
module FDoc.RecursionSchemes where
|
||||
|
||||
import Data.Range
|
||||
import Data.Record
|
||||
import Category
|
||||
import Term
|
||||
import Syntax
|
||||
import Prologue
|
||||
import Prelude
|
||||
import FDoc.Term
|
||||
|
||||
data NewField = NewField deriving (Show)
|
||||
|
||||
{-
|
||||
Anamorphism -- add a new field to each term's Record fields
|
||||
|
||||
ana :: (a -> Base t a) -- a (Base t)-coalgebra
|
||||
-> a -- seed
|
||||
-> t -- resulting fixed point
|
||||
|
||||
Anamorphism as a recursion scheme "builds up" a recursive structure.
|
||||
Anamorphisms work by using a coalgebra, which maps a seed value to a fixed point
|
||||
structure.
|
||||
|
||||
The example below adds a new field to the `Record` fields.
|
||||
-}
|
||||
indexedTermAna :: [Text] -> Term Syntax (Record '[NewField, Range, Category])
|
||||
indexedTermAna childrenLeaves = ana coalgebra (indexedTerm childrenLeaves)
|
||||
where
|
||||
coalgebra term = (NewField :. (extract term)) :< unwrap term
|
||||
|
||||
{-
|
||||
Catamorphism example -- add a new field to each term's Record fields
|
||||
|
||||
cata :: (Base t a -> a) -- a (Base t)-algebra
|
||||
-> t -- fixed point
|
||||
-> a -- result
|
||||
|
||||
Catamorphism as a recursion scheme "tears down" a recursive structure.
|
||||
Catamorphisms work by using an algebra, which maps a shape in our fixed point
|
||||
structure to a new shape.
|
||||
|
||||
The example below adds a new field to the `Record` fields.
|
||||
-}
|
||||
indexedTermCata :: [Text] -> Term Syntax (Record '[NewField, Range, Category])
|
||||
indexedTermCata childrenLeaves = cata algebra (indexedTerm childrenLeaves)
|
||||
where
|
||||
algebra :: Functor f => CofreeF f (Record t) (Cofree f (Record (NewField : t))) -> Cofree f (Record (NewField : t))
|
||||
algebra term = cofree $ (NewField :. headF term) :< tailF term
|
||||
|
||||
{-
|
||||
Anamorphism -- construct a Term from a string
|
||||
|
||||
The example below shows how to build up a recursive Term structure from a string
|
||||
representation.
|
||||
|
||||
Example usage:
|
||||
|
||||
stringToTermAna "indexed" =>
|
||||
CofreeT (Identity ( (Range {start = 1, end = 10} :. MethodCall :. Nil)
|
||||
:<
|
||||
Indexed
|
||||
[ CofreeT (Identity ( (Range {start = 1, end = 10} :. MethodCall :. Nil) :< Leaf "leaf1" ) )
|
||||
, CofreeT (Identity ( (Range {start = 1, end = 10} :. MethodCall :. Nil) :< Leaf "leaf2" ) )
|
||||
, CofreeT (Identity ( (Range {start = 1, end = 10} :. MethodCall :. Nil) :< Leaf "leaf3" ) )
|
||||
] ))
|
||||
|
||||
First step is to match against the "indexed" string and begin building up a Cofree Indexed structure:
|
||||
|
||||
CofreeT (Identity ( (Range 1 10 :. Category.MethodCall :. Nil) :< Indexed ["leaf1", "leaf2", "leaf3"] ) )
|
||||
|
||||
While building up the `Indexed` structure, we continue to recurse over the
|
||||
`Indexed` terms ["leaf1", "leaf2", "leaf3"]. These are pattern matched using
|
||||
the catch all `_` and default to `Leaf` Syntax shapes:
|
||||
|
||||
CofreeT (Identity ( (Range 1 10 :. Category.MethodCall :. Nil) :< Leaf "leaf1" ) )
|
||||
CofreeT (Identity ( (Range 1 10 :. Category.MethodCall :. Nil) :< Leaf "leaf2" ) )
|
||||
CofreeT (Identity ( (Range 1 10 :. Category.MethodCall :. Nil) :< Leaf "leaf3" ) )
|
||||
|
||||
These structures are substituted in place of ["leaf1", "leaf2", "leaf3"] in
|
||||
the new cofree `Indexed` structure, resulting in a expansion of all possible
|
||||
string terms.
|
||||
-}
|
||||
stringToTermAna :: Text -> Term Syntax (Record '[Range, Category])
|
||||
stringToTermAna = ana coalgebra
|
||||
where
|
||||
coalgebra representation = case representation of
|
||||
"indexed" -> (Range 1 10 :. Category.MethodCall :. Nil) :< Indexed ["leaf1", "leaf2", "leaf3"]
|
||||
_ -> (Range 1 10 :. Category.MethodCall :. Nil) :< Leaf representation
|
||||
|
||||
{-
|
||||
Catamorphism -- construct a list of Strings from a recursive Term structure.
|
||||
|
||||
The example below shows how to tear down a recursive Term structure into a list
|
||||
of String representation.
|
||||
-}
|
||||
termToStringCata :: Term Syntax (Record '[Range, Category]) -> [Text]
|
||||
termToStringCata = cata algebra
|
||||
where
|
||||
algebra term = case term of
|
||||
(_ :< Leaf value) -> [value]
|
||||
(_ :< Indexed values) -> ["indexed"] <> Prologue.concat values
|
||||
_ -> ["unknown"]
|
||||
|
||||
{-
|
||||
Hylomorphism -- An anamorphism followed by a catamorphism
|
||||
|
||||
hylo :: Functor f => (f b -> b) -- an algebra
|
||||
-> (a -> f a) -- a coalgebra
|
||||
-> a -- seed value
|
||||
-> b -- result
|
||||
|
||||
Hylomorphisms work by first applying a coalgebra (anamorphism) to build up a
|
||||
structure. An algebra (catamorphism) is then applied to this structure. Because
|
||||
of fusion the anamorphism and catamorphism occur in a single pass rather than
|
||||
two separate traversals.
|
||||
|
||||
The example below shows how our algebra and coalgebra defined in the
|
||||
termToStringCata and stringToTermAna can be utilized as a hylomorphism.
|
||||
|
||||
Example Usage:
|
||||
stringTermHylo "indexed" => ["indexed", "leaf1", "leaf2", "leaf3"]
|
||||
|
||||
-}
|
||||
stringTermHylo :: Text -> [Text]
|
||||
stringTermHylo = hylo algebra coalgebra
|
||||
where
|
||||
algebra term = case term of
|
||||
(_ :< Leaf value) -> [value]
|
||||
(_ :< Indexed values) -> ["indexed"] <> Prologue.concat values
|
||||
_ -> ["unknown"]
|
||||
coalgebra stringRepresentation = case stringRepresentation of
|
||||
"indexed" -> (Range 1 10 :. Category.MethodCall :. Nil) :< Indexed ["leaf1", "leaf2", "leaf3"]
|
||||
_ -> (Range 1 10 :. Category.MethodCall :. Nil) :< Leaf stringRepresentation
|
||||
|
||||
{-
|
||||
Paramorphism -- primitive recursion that maintains a reference to the original value and its computed value.
|
||||
|
||||
para :: (Base t (t, a) -> a) -- an algebra that takes a tuple of the last input
|
||||
-> t -- fixed point
|
||||
-> a -- result
|
||||
|
||||
Paramorphisms, like all recursion schemes, work via a bottom up traversal
|
||||
(leaves to root), in which an algebra is applied to every node in the recursive
|
||||
structure. The difference between paramorphisms and catamorphisms is the algebra
|
||||
receives a tuple of the original subobject and its computed value (t, a) where
|
||||
`t` is the original suboject and `a` is the computed value.
|
||||
|
||||
The example implementation below calculates a string representation for each
|
||||
Syntax type, flattening the recursive structure into a one dimensional list to
|
||||
tuples. The tuple contains the original syntax subobject, and its computed
|
||||
string representation. This example aims to showcase how paramorphisms work by
|
||||
returning a final list of tuples that mimics the intermediate tuple shapes the
|
||||
algebra receives throughout the bottom up traversal.
|
||||
|
||||
Example Usage:
|
||||
let terms = indexedTerm ["leaf1", "leaf2", "leaf3"]
|
||||
termPara terms = Recurse over the structure to start at the leaves (bottom up traversal):
|
||||
|
||||
tuple3 = ( CofreeT (Identity ((Range {start = 1, end = 10} :. MethodCall :. Nil) :< Leaf "leaf3")), "leaf3" ) : []
|
||||
|
||||
Continue the traversal from leaves to root:
|
||||
|
||||
tuple2:3 = ( CofreeT (Identity ((Range {start = 1, end = 10} :. MethodCall :. Nil) :< Leaf "leaf2")), "leaf2") : tuple3
|
||||
|
||||
tuple1:2:3 = ( CofreeT (Identity ((Range {start = 1, end = 10} :. MethodCall :. Nil) :< Leaf "leaf1" )), "leaf1") : tuple2:3
|
||||
|
||||
Compute the root:
|
||||
tupleIndexed:1:2:3 = ( CofreeT (Identity ((Range {start = 1, end = 10} :. MethodCall :. Nil) :< Indexed [])), "indexed" ) : tuple1:2:3
|
||||
|
||||
Final shape:
|
||||
[ (CofreeT (Identity ((Range {start = 1, end = 10} :. MethodCall :. Nil) :< Indexed [])) , "indexed")
|
||||
, (CofreeT (Identity ((Range {start = 1, end = 10} :. MethodCall :. Nil) :< Leaf "leaf1")), "leaf1")
|
||||
, (CofreeT (Identity ((Range {start = 1, end = 10} :. MethodCall :. Nil) :< Leaf "leaf2")), "leaf2")
|
||||
, (CofreeT (Identity ((Range {start = 1, end = 10} :. MethodCall :. Nil) :< Leaf "leaf3")), "leaf3")
|
||||
]
|
||||
|
||||
-}
|
||||
termPara :: Term Syntax (Record '[Range, Category]) -> [(Term Syntax (Record '[Range, Category]), Text)]
|
||||
termPara = para algebra
|
||||
where
|
||||
algebra term = case term of
|
||||
(annotation :< Leaf representation) -> [(cofree (annotation :< Leaf representation), representation)]
|
||||
(annotation :< Indexed values) -> [(cofree (annotation :< Indexed []), "indexed")] <> (values >>= Prelude.snd)
|
||||
_ -> [(cofree ((Range 1 10 :. Category.MethodCall :. Nil) :< Leaf "unknown"), "unknown")]
|
@ -1,67 +0,0 @@
|
||||
{-# LANGUAGE DataKinds, TypeOperators #-}
|
||||
module FDoc.Term where
|
||||
|
||||
import Data.Range
|
||||
import Data.Record
|
||||
import Category
|
||||
import Term
|
||||
import Syntax
|
||||
import Prologue
|
||||
|
||||
{-
|
||||
|
||||
Constructs a Syntax.Leaf using the polymorphic type variable `leaf`.
|
||||
|
||||
This is in the TermF shape: CofreeF f a b where
|
||||
f is the functor (Syntax.Leaf `leaf`)
|
||||
a is the annotation (Record '[Range, Category])
|
||||
b is the same type of functor defined by f
|
||||
|
||||
Two common convenience operations when working with CofreeF (for docs, see
|
||||
Control.Comonad.Trans.Cofree.Types.CofreeF) are `headF` and `tailF`. `headF`
|
||||
return the annotation portion of the CofreeF structure, and `tailF` returns the
|
||||
functor portion (Syntax).
|
||||
|
||||
Example (from GHCi):
|
||||
|
||||
> let leaf = leafTermF "example"
|
||||
> headF leaf
|
||||
> Range {start = 1, end = 10} :. MethodCall :. Nil
|
||||
> tailF leaf
|
||||
> Leaf "example"
|
||||
|
||||
-}
|
||||
|
||||
leafTermF :: Text -> TermF Syntax (Record '[Range, Category]) b
|
||||
leafTermF leaf = (Range 1 10 :. Category.MethodCall :. Nil) :< Leaf leaf
|
||||
|
||||
{-
|
||||
|
||||
Constructs a Syntax.Leaf using the polymorphic type variable `leaf`.
|
||||
|
||||
This is in the Term shape: Cofree f a where
|
||||
f is the functor (Syntax.Leaf `leaf`)
|
||||
a is the annotation (Record '[Range, Category])
|
||||
|
||||
Two common convenience operations when working with Cofree (for docs, see
|
||||
Control.Comonad.Trans.Cofree.Types.Cofree) are `extract` and `unwrap`. `extract`
|
||||
returns the annotation portion of the Cofree structure, and `unwrap` returns the
|
||||
functor portion (Syntax).
|
||||
|
||||
Example (from GHCi):
|
||||
|
||||
> let leaf = leafTerm "example"
|
||||
> extract leaf
|
||||
> Range {start = 1, end = 10} :. MethodCall :. Nil
|
||||
> unwrap leaf
|
||||
> Leaf "example"
|
||||
|
||||
-}
|
||||
leafTerm :: Text -> Cofree Syntax (Record '[Range, Category])
|
||||
leafTerm = cofree . leafTermF
|
||||
|
||||
indexedTermF :: [Text] -> TermF Syntax (Record '[Range, Category]) (Term Syntax (Record '[Range, Category]))
|
||||
indexedTermF leaves = (Range 1 10 :. Category.MethodCall :. Nil) :< Indexed (leafTerm <$> leaves)
|
||||
|
||||
indexedTerm :: [Text] -> Term Syntax (Record '[Range, Category])
|
||||
indexedTerm leaves = cofree $ indexedTermF leaves
|
Loading…
Reference in New Issue
Block a user