-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nested or recursive barbies? #13
Comments
Indeed, nested barbies would be quite useful to support, but they proved to be tricky so far. The main issue is that they just don't fit. Let's take data InnerBarbie f
= InnerBarbie
{ innerData :: f String
} deriving (Generic, FunctorB)
data OuterBarbie f
= OuterBarbie
{ innerBarbie :: f (InnerBarbie f)
}
instance FunctorB OuterBarbie where
bmap h (OuterBarbie fibf)
= -- because InnerBarbie is a FunctorB, we can use `bmap h` on it; we only need to
-- pass it through the outer f with an `fmap`; unfortunately this won't typecheck...
OuterBarbie (bmap h <$> fibf) The problem is that, because of the All that said, I've been playing recently with a construction that may let us express nested barbies, hopefully without hurting usability too much (it requires class Functor2B b where
bmap2 :: (forall a . f a -> g a) -> b f x -> b g x We can derive generic instances for this class in the same way. Intuitively, if type BifunctorB b = (Functor2B b, (forall f. FunctorB (b f)))
bfirst :: BifunctorB b => (forall a. f a -> f' a) -> b f g -> b f' g
bfirst = bmap2
bsecond :: BifunctorB b => (forall a. g a -> g' a) -> b f g -> b f g'
bsecond = bmap ( Now, let's rewrite data OuterBarbie' f g
= OuterBarbie' (f (InnerBarbie g))
type OuterBarbie f = OuterBarbie' f f
instance Functor2B OuterBarbie' where
bmap2 h (OuterBarbie' fibg)
= OuterBarbie' (h fibg)
instance Functor f => FunctorB (OuterBarbie' f) where
bmap h (OuterBarbie' fibg)
= OuterBarbie (bmap h <$> fibg) Notice that, because of the newtype Nested b f
= Nested (b (Yoneda f) f)
asNested :: (Functor2B b, Functor f) => b f f -> Nested b f
asNested bff
= Nested (bmap2 liftYoneda bff)
runNested :: Functor2B b => Nested b f -> b f f
runNested (Nested byf)
= bmap2 lowerYoneda byf
instance (Functor2B b, (forall f. FunctorB (b (Yoneda f) f)) => FunctorB (Nested b f) where
bmap h (Nested byf)
= Nested $ bmap2 (hoistYoneda h) $ bmap h byf So, in the end this means that to work with nested barbies, one would need something like |
Version 2.0.0.0 supports nested barbies via bifunctors. See https://hackage.haskell.org/package/barbies-2.0.0.0/docs/Barbies.html#g:3 |
@jcpetruzza can you give an AST example?
|
Hi @yairchu, the quote was not mine, but I think the general idea of using barbies for ASTs would be something along the lines of: {-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
-- NB. I'm adding a Let constructor that wasn't in your example
data Expr (f :: String -> Type)
= Var (f "Var") Text
| App (f "App") (Expr f) (Expr f)
| Let (f "Let") Text (Expr f)
| Lam (f "Lam") Text (Typ f) (Expr f)
data Typ (f :: String -> Type)
= IntT (f "IntT")
| FuncT (f "FuncT") (Typ f) (Typ f)
-- NB. Unit is Barbies.Unit
data TypeCheckedAndDesugared (s :: String) where
CVar :: (Typ Unit) -> TypeCheckedAndDesugared "Var"
CApp :: Unit -> TypeCheckedAndDesugared "App"
CLam :: Typ Unit -> TypeCheckedAndDesugared "Lam" Now, if you get something of type
Now, in this example, Hope this makes sense! (the example is untested, but should hopefully work after minor fixes) |
@jcpetruzza Thanks for the elaboration! So the given To explain what I mean, if it was for nesting AST subexpressions, one could use |
At least in my example, yeah.
Let me see if I understand. You'd like something like: data Expr f
= Var Text
| App (f (Expr f)) (f (Expr f))
| Lam Text (f (Expr f)) So that What you could do:
example :: Expr MaybeParsed
example = App ParsedApp (Var ParsedVar x) (Invalid (ParseError "syntax error: expected blah..."))
data Parsed err (t :: String) where
ParsedVar :: Parsed err "Var"
ParsedApp :: Parsed err "App"
ParsedLam :: Parsed er "Lam"
ParseError :: err -> Parsed err "Invalid"
type MaybeParsed = Parsed String
-- An `Expr ParsedOk` has no parsing errors
type ParsedOk = Parsed Void
class MyFunctorB b where
mybmap :: (forall a . Functor f => f a -> g a) -> b f -> b g
instance MyFunctorB Expr where
mybmap h = .... |
It seems that the
AllB
andAllBF
constraints are insufficient for type hierarchies which nest or recur barbies, threading through the clothing parameter. I made a gist with a minimal test case, and included the type errors as reported by GHCI 8.6.4:https://gist.github.com/eamsden/2d6c89f899b84b3ad9d5b24d15995fac
This would be very useful e.g. for compilers with rich ASTs, using the clothing types to make fields optional or label fields with source locations and the text they were parsed from, but I can't get it to work.
The text was updated successfully, but these errors were encountered: