Where communities thrive

  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
Repo info
    Xavier Denis

    @lambdageek how do I reuse generic implementations for functorised ASTs?

    data Expr a = Var a (Name (Expr a))
    | Other Constructors

    I'd like Alpha to ignore the annotations (a). However, writing a manual implementation to the class is tedious (given there are 6 methods that need to be written) if I only need to change 1-2 cases. Is there a way to default to the generic implementation in other cases?

    Xavier Denis
    I'd also like GHC to not require a Alpha a context
    Aleksey Kliger (λgeek)

    Hey, sorry I didn't notice your message @xldenis . All the methods have default implementations provided that Expr a is an instance of Generic, so you can just change the ones you want. If you want to call down to the generic impl, you would need to do something like

    (GHC.Generics.to .  gopen ctx pat . GHC.Generics.from) subTerm

    The various g* functions are defined in Unbound.Generics.LocallyNameless.Alpha. If you can stand a newtype, what I usually do is something like

    newtype Annot a = Annot {getAnnot :: a }
      deriving ({- everything -})

    and then write an instance for Annot a that just uses (==) and compare and is the identity for functions like open and close and then populate your AST with Annot a values

    Valentin Robert
    Hi @lambdageek , I'm having trouble understanding the type of fv, could you provide a little explanation?
    Aleksey Kliger (λgeek)
    @Ptival you can think of the type of fv as (Alpha a, Typeable b) => Fold a (Name b) in the sense of the lens libary's Fold. What that means, roughly is that given some syntax structure a (which is an instance of Alpha) you can use fv to iterate over free variables Name b that occur within it and summarize them using some kind of Monoid very similar to how the Foldable typeclass works. More concretely, if you have some Expr type that has variables of type Name Expr in it, you can do toListOf fv :: Expr -> [Name Expr] (using the definition of toListOf from lens, or the one in Unbound.Generics.LocallyNameless.Internal.Fold) more generally foldMapOf fv :: Monoid r => (Name Expr -> r) -> Expr -> r lets you use some other monoid to summarize the free variables. One that I find useful all the time, for example, is Data.Set.Lens.setOf fv :: Expr -> Data.Set.Set (Name Expr) (setOf is in lens and Data.Set.Set is from containers)
    Jake Zimmerman
    Super late to the convo on this one, but since I just recently got a grasp for fv and lenses more generally, this is one of the ways I frequently use fv: checking whether a variable is in the free variables of another term:
    import           Control.Lens                     (noneOf)
    import           Data.Typeable                    (Typeable)
    import           Unbound.Generics.LocallyNameless
    -- This uses lenses because unbound-generic's fv supports lenses!
    -- fv is a Getter combinator that gets the free variables of a structure, and
    -- noneOf lets us fold over that structure, checking that none of them are (== t)
    notInFreeVars :: (Alpha a, Typeable a) => Name a -> a -> Bool
    notInFreeVars t t1 = noneOf fv (== t) t1
    Aleksey Kliger (λgeek)
    Very nice! I'm glad it turned out to be useful. (This is kind of what I hoped it would be useful for, but I never quite found a need for it in my own code - always seemed prudent to just use toListOf or toSetOf)
    Mark Lemay
    Sorry if this is a dumb question:
    I have a simple lambda language and I want to do equality checking on it . I can't figure out how to unpack 2 lambda's simultaneously so they get the same De Bruijn index. or alternatively how to pick a new free var from the 2 expressions that I can apply to both.
    Any thoughts?
    Aleksey Kliger (λgeek)
    @marklemay You want unbind2 or lunbind2. If you have Lam (Bind Var Expr) in your datatype definition, and Lam b1 and Lam b2, you can do something like this in the Fresh m monad: Just (v1, e1, _, e2) <- unbind e1 e2 to get at the subexpressions. If you are in LFresh m, then lunbind b1 b2 $ \(Just (v1, e1, _, e2) -> ... ) will work.
    In a more general setting (for example if your have Lam (Bind (Var, Embed Type) Expr) - ie, the pattern portion of the Bind is more complicated than just a single variable, you will want to hold on to both sides when you unbind2. something like Just (p1, e1, p2, e2) <- unbind b1 b2. And then unpack p1 and p2 - the variables will be renamed when unbinding so that they are same, but the Embeded types may differ.
    Mark Lemay