reprimTerm ::
  FreshName n =>
  MonadFresh m =>
  Term k Core.Prim n a ->
  ExceptT (ReprimError n a) m (Term k X64.Prim n a)
reprimTerm = \case
  Return ar (Call ac n xs) ->
    pure $
      Return ar (Call ac n xs)

  Return a tl -> do
    -- TODO should be based on arity of tail, not just [n]
    -- TODO need to do arity inference before this is possible.
    n <- newFresh
    let_tail <- reprimTail a [n] tl
    pure . let_tail $
      Return a (Copy a [Variable a n])

  If a k i t e -> do
    If a k i
      <$> reprimTerm t
      <*> reprimTerm e

  Let a ns tl tm -> do
    let_tail <- reprimTail a ns tl
    let_tail <$> reprimTerm tm

  LetRec a bs tm ->
    LetRec a
      <$> reprimBindings bs
      <*> reprimTerm tm
reprimTerm ::
  FreshName n =>
  MonadFresh m =>
  Term k Core.Prim n a ->
  ExceptT (ReprimError n a) m (Term k X64.Prim n a)
reprimTerm = \case
  Return ar (Call ac n xs) ->
    pure $
      Return ar (Call ac n xs)

  Return a tl -> do
    -- TODO should be based on arity of tail, not just [n]
    -- TODO need to do arity inference before this is possible.
    n <- newFresh
    let_tail <- reprimTail a [n] tl
    pure . let_tail $
      Return a (Copy a [Variable a n])

  If a k i t e -> do
    If a k i
      <$> reprimTerm t
      <*> reprimTerm e

  Let a ns tl tm -> do
    let_tail <- reprimTail a ns tl
    let_tail <$> reprimTerm tm

  LetRec a bs tm ->
    LetRec a
      <$> reprimBindings bs
      <*> reprimTerm tm
reprimTerm = \case
  Return ar (Call ac n xs) ->
    pure $
      Return ar (Call ac n xs)

  Return a tl -> do
    -- TODO should be based on arity of tail, not just [n]
    -- TODO need to do arity inference before this is possible.
    n <- newFresh
    let_tail <- reprimTail a [n] tl
    pure . let_tail $
      Return a (Copy a [Variable a n])

  If a k i t e -> do
    If a k i
      <$> reprimTerm t
      <*> reprimTerm e

  Let a ns tl tm -> do
    let_tail <- reprimTail a ns tl
    let_tail <$> reprimTerm tm

  LetRec a bs tm ->
    LetRec a
      <$> reprimBindings bs
      <*> reprimTerm tm