mkOp :: Eq a => Op -> Op2 (Skel a)
mkOp op = go where
  Zero  `go` p     = p
  p     `go` Zero  = p

  Act c `go` p
    | Prll _ <- op,
      c `elemS` p  = p

    -- Avoid redundancies on the left: c * (c * sk) --> c * sk
    | Op op' (Act d) _ <- p,
      op `compat` op',
      c == d       = p

    | Dot <- op,
      c `elemS` p  = unknownS (Act c) (pruneEq c p)

  p     `go` Act c
    | Prll _ <- op,
      c `elemS` p  = p

  Act c `go` Act d
    | c == d       = Act d

  -- Right nesting: (x * y) * z --> x * (y * z)
  -- Which also enables further reductions when the result is built back.
  Op op' p0 p1 `go` q
    | op `compat` op'
                   = mkOp op p0 (mkOp op p1 q)

  p     `go` q     = Op op p q
mkOp :: Eq a => Op -> Op2 (Skel a)
mkOp op = go where
  Zero  `go` p     = p
  p     `go` Zero  = p

  Act c `go` p
    | Prll _ <- op,
      c `elemS` p  = p

    -- Avoid redundancies on the left: c * (c * sk) --> c * sk
    | Op op' (Act d) _ <- p,
      op `compat` op',
      c == d       = p

    | Dot <- op,
      c `elemS` p  = unknownS (Act c) (pruneEq c p)

  p     `go` Act c
    | Prll _ <- op,
      c `elemS` p  = p

  Act c `go` Act d
    | c == d       = Act d

  -- Right nesting: (x * y) * z --> x * (y * z)
  -- Which also enables further reductions when the result is built back.
  Op op' p0 p1 `go` q
    | op `compat` op'
                   = mkOp op p0 (mkOp op p1 q)

  p     `go` q     = Op op p q
mkOp op = go where
  Zero  `go` p     = p
  p     `go` Zero  = p

  Act c `go` p
    | Prll _ <- op,
      c `elemS` p  = p

    -- Avoid redundancies on the left: c * (c * sk) --> c * sk
    | Op op' (Act d) _ <- p,
      op `compat` op',
      c == d       = p

    | Dot <- op,
      c `elemS` p  = unknownS (Act c) (pruneEq c p)

  p     `go` Act c
    | Prll _ <- op,
      c `elemS` p  = p

  Act c `go` Act d
    | c == d       = Act d

  -- Right nesting: (x * y) * z --> x * (y * z)
  -- Which also enables further reductions when the result is built back.
  Op op' p0 p1 `go` q
    | op `compat` op'
                   = mkOp op p0 (mkOp op p1 q)

  p     `go` q     = Op op p q