-- automatically derived

zipWithFlatTermF :: (x -> y -> z) -> FlatTermF x -> FlatTermF y -> Maybe (FlatTermF z)
zipWithFlatTermF f = go
  where go (GlobalDef x) (GlobalDef y) | x == y = Just $ GlobalDef x

        go UnitValue UnitValue = Just UnitValue
        go UnitType UnitType = Just UnitType
        go (PairValue x1 x2) (PairValue y1 y2) = Just (PairValue (f x1 y1) (f x2 y2))
        go (PairType x1 x2) (PairType y1 y2) = Just (PairType (f x1 y1) (f x2 y2))
        go (PairLeft x) (PairLeft y) = Just (PairLeft (f x y))
        go (PairRight x) (PairRight y) = Just (PairLeft (f x y))

        go (RecordValue mx) (RecordValue my)
          | Map.keys mx == Map.keys my =
              Just $ RecordValue $ Map.intersectionWith f mx my
        go (RecordSelector x fx) (RecordSelector y fy)
          | fx == fy = Just $ RecordSelector (f x y) fx
        go (RecordType mx) (RecordType my)
          | Map.keys mx == Map.keys my =
              Just $ RecordType (Map.intersectionWith f mx my)

        go (CtorApp cx lx) (CtorApp cy ly)
          | cx == cy = Just $ CtorApp cx (zipWith f lx ly)
        go (DataTypeApp dx lx) (DataTypeApp dy ly)
          | dx == dy = Just $ DataTypeApp dx (zipWith f lx ly)
        go (Sort sx) (Sort sy) | sx == sy = Just (Sort sx)
        go (NatLit i) (NatLit j) | i == j = Just (NatLit i)
        go (FloatLit fx) (FloatLit fy)
          | fx == fy = Just $ FloatLit fx
        go (DoubleLit fx) (DoubleLit fy)
          | fx == fy = Just $ DoubleLit fx
        go (StringLit s) (StringLit t) | s == t = Just (StringLit s)
        go (ArrayValue tx vx) (ArrayValue ty vy)
          | V.length vx == V.length vy = Just $ ArrayValue (f tx ty) (V.zipWith f vx vy)
        go (ExtCns (EC xi xn xt)) (ExtCns (EC yi _ yt))
          | xi == yi = Just (ExtCns (EC xi xn (f xt yt)))

        go _ _ = Nothing
zipWithFlatTermF :: (x -> y -> z) -> FlatTermF x -> FlatTermF y -> Maybe (FlatTermF z)
zipWithFlatTermF f = go
  where go (GlobalDef x) (GlobalDef y) | x == y = Just $ GlobalDef x

        go UnitValue UnitValue = Just UnitValue
        go UnitType UnitType = Just UnitType
        go (PairValue x1 x2) (PairValue y1 y2) = Just (PairValue (f x1 y1) (f x2 y2))
        go (PairType x1 x2) (PairType y1 y2) = Just (PairType (f x1 y1) (f x2 y2))
        go (PairLeft x) (PairLeft y) = Just (PairLeft (f x y))
        go (PairRight x) (PairRight y) = Just (PairLeft (f x y))

        go (RecordValue mx) (RecordValue my)
          | Map.keys mx == Map.keys my =
              Just $ RecordValue $ Map.intersectionWith f mx my
        go (RecordSelector x fx) (RecordSelector y fy)
          | fx == fy = Just $ RecordSelector (f x y) fx
        go (RecordType mx) (RecordType my)
          | Map.keys mx == Map.keys my =
              Just $ RecordType (Map.intersectionWith f mx my)

        go (CtorApp cx lx) (CtorApp cy ly)
          | cx == cy = Just $ CtorApp cx (zipWith f lx ly)
        go (DataTypeApp dx lx) (DataTypeApp dy ly)
          | dx == dy = Just $ DataTypeApp dx (zipWith f lx ly)
        go (Sort sx) (Sort sy) | sx == sy = Just (Sort sx)
        go (NatLit i) (NatLit j) | i == j = Just (NatLit i)
        go (FloatLit fx) (FloatLit fy)
          | fx == fy = Just $ FloatLit fx
        go (DoubleLit fx) (DoubleLit fy)
          | fx == fy = Just $ DoubleLit fx
        go (StringLit s) (StringLit t) | s == t = Just (StringLit s)
        go (ArrayValue tx vx) (ArrayValue ty vy)
          | V.length vx == V.length vy = Just $ ArrayValue (f tx ty) (V.zipWith f vx vy)
        go (ExtCns (EC xi xn xt)) (ExtCns (EC yi _ yt))
          | xi == yi = Just (ExtCns (EC xi xn (f xt yt)))

        go _ _ = Nothing
zipWithFlatTermF f = go
  where go (GlobalDef x) (GlobalDef y) | x == y = Just $ GlobalDef x

        go UnitValue UnitValue = Just UnitValue
        go UnitType UnitType = Just UnitType
        go (PairValue x1 x2) (PairValue y1 y2) = Just (PairValue (f x1 y1) (f x2 y2))
        go (PairType x1 x2) (PairType y1 y2) = Just (PairType (f x1 y1) (f x2 y2))
        go (PairLeft x) (PairLeft y) = Just (PairLeft (f x y))
        go (PairRight x) (PairRight y) = Just (PairLeft (f x y))

        go (RecordValue mx) (RecordValue my)
          | Map.keys mx == Map.keys my =
              Just $ RecordValue $ Map.intersectionWith f mx my
        go (RecordSelector x fx) (RecordSelector y fy)
          | fx == fy = Just $ RecordSelector (f x y) fx
        go (RecordType mx) (RecordType my)
          | Map.keys mx == Map.keys my =
              Just $ RecordType (Map.intersectionWith f mx my)

        go (CtorApp cx lx) (CtorApp cy ly)
          | cx == cy = Just $ CtorApp cx (zipWith f lx ly)
        go (DataTypeApp dx lx) (DataTypeApp dy ly)
          | dx == dy = Just $ DataTypeApp dx (zipWith f lx ly)
        go (Sort sx) (Sort sy) | sx == sy = Just (Sort sx)
        go (NatLit i) (NatLit j) | i == j = Just (NatLit i)
        go (FloatLit fx) (FloatLit fy)
          | fx == fy = Just $ FloatLit fx
        go (DoubleLit fx) (DoubleLit fy)
          | fx == fy = Just $ DoubleLit fx
        go (StringLit s) (StringLit t) | s == t = Just (StringLit s)
        go (ArrayValue tx vx) (ArrayValue ty vy)
          | V.length vx == V.length vy = Just $ ArrayValue (f tx ty) (V.zipWith f vx vy)
        go (ExtCns (EC xi xn xt)) (ExtCns (EC yi _ yt))
          | xi == yi = Just (ExtCns (EC xi xn (f xt yt)))

        go _ _ = Nothing