agda / agda2hs

Compiling Agda code to readable Haskell

Home Page:https://agda.github.io/agda2hs

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Remove "smart" generic tuple handling

flupe opened this issue · comments

Currently we have a generic implementation of n-uples in agda2hs.
That is, Tuple is defined by large elimination over a list of types, so that we have a unified way of representing tuples of different lengths. While nice in theory, the only real benefit we get is easy definition of typeclass instances in the Haskell prelude.

But there are way too many downsides:

  • The large-elimination definition was required to appease the positivity checker (#95, #96) but is cumbersome and leaky.
  • We have to add many checks to ensure Tuple is always applied to a concrete list of types:
    isSpecialType :: QName -> Maybe (QName -> Elims -> C (Hs.Type ()))
    isSpecialType = prettyShow >>> \case
    "Haskell.Prim.Tuple.Tuple" -> Just tupleType
    "Haskell.Prim.Tuple._×_" -> Just tupleType
    "Haskell.Prim.Tuple._×_×_" -> Just tupleType
    _ -> Nothing
    tupleType' :: C Doc -> Term -> C [Term]
    tupleType' err xs =
    reduce xs >>= \case
    Def q es
    | [] <- vis es, q ~~ "Agda.Builtin.Unit.⊤" -> pure []
    | [_,_] <- vis es, q ~~ "Haskell.Prim.Tuple.Pair" -> pairToTuple es
    _ -> genericDocError =<< err
    where
    vis es = [ unArg a | Apply a <- es, visible a ]
    pairToTuple :: Elims -> C [Term]
    pairToTuple es
    | Just [x, xs] <- allApplyElims es = (unArg x:) <$> tupleType' err (unArg xs)
    | otherwise = genericDocError =<< text "Bad arguments for Pair: " <?> text (show es)
    tupleType :: QName -> Elims -> C (Hs.Type ())
    tupleType q es = do
    let err = sep [ prettyTCM (Def q es)
    , text "is not a concrete sequence of types."
    ]
    xs <- reduce (Def q es) >>= tupleType' err
    ts <- mapM compileType xs
    return $ Hs.TyTuple () Hs.Boxed ts
  • We have to add special checks for tuple terms for the same reason:
    isSpecialCon :: QName -> Maybe (ConHead -> ConInfo -> Elims -> C (Hs.Exp ()))
    isSpecialCon = prettyShow >>> \case
    "Haskell.Prim.Tuple._;_" -> Just tupleTerm
    _ -> Nothing
    tupleTerm :: ConHead -> ConInfo -> Elims -> C (Hs.Exp ())
    tupleTerm cons i es = do
    let v = Con cons i es
    err = sep [ text "Tuple value"
    , nest 2 $ prettyTCM v
    , text "does not have a known size." ]
    xs <- makeList' "Agda.Builtin.Unit.tt" "Haskell.Prim.Tuple._;_" err v
    ts <- mapM compileTerm xs
    return $ Hs.Tuple () Hs.Boxed ts
  • Since Agda inlines let bindings entirely, using pattern-matching let bindings on tuples is currently buggy (#215) and we can really only easily fix it for 2-uples (#216).
  • I don't think we support tuple sections, a quite useful and commonplace Haskell feature.

I hope these points convey properly that perhaps we should be pragmatic and have a simpler implementation for tuples. Let's remove all genericity and implement n-uples separately for n between 2 and I don't know, let's say, 5.