{-# LANGUAGE LambdaCase, GADTs, DataKinds, MagicHash, StandaloneKindSignatures #-}
-- | A DSL for evaluating remote expressions on the (possibly) remote debuggee process
--
-- Meant to be imported qualified @as Remote@ for use with @QualifiedDo@.
--
-- @
-- import GHC.Debugger.Runtime.Eval.RemoteExpr (RemoteExpr)
-- import qualified GHC.Debugger.Runtime.Eval.RemoteExpr as Remote
-- @
module GHC.Debugger.Runtime.Eval.RemoteExpr
  (
  -- * Building remote expressions
    RemoteExpr
  , var, ref, untypedRef
  , lit, raw
  , app, appRef
  , withUnboxed
  , fmap, (<$>)
  , pure, return
  , (>>=), (>>)

  -- * Evaluating remote expressions
  , eval, evalIO, evalString, evalIOList, evalIOString
  ) where

import Prelude hiding (pure, return, (>>=), (>>), fmap, (<$>))
import qualified Prelude
import qualified Data.Kind as Kind
import Control.Monad.Except
import GHC.Exts
import GHC
import Control.Monad.Reader
import GHCi.RemoteTypes

import GHC.Debugger.Monad
import GHC.Debugger.Runtime.Eval (handleSingStatus, BadEvalStatus(..), EvalExpr(..))
import qualified GHC.Debugger.Runtime.Eval as Raw
import GHC.Debugger.Runtime.Compile

--------------------------------------------------------------------------------
-- * Higher-level: eDSL for (possibly) remote evaluation on the debuggee
--------------------------------------------------------------------------------

-- | A remote expression to be evaluated on the debuggee process.
-- Note: the remote expression must have a boxed representation type.
type RemoteExpr :: forall l. TYPE (BoxedRep l) -> Kind.Type
data RemoteExpr t where

  -- | Parse, compile, and load a raw expression string onto the remote process.
  -- This is a low-level escape hatch; prefer using the other constructors.
  -- The loaded expression is cached by its string.
  RemRaw    :: String -> RemoteExpr a

  -- | A top-level or in-another-module name (aka external name) in the debuggee process.
  -- The list of strings is the list of (fully-qualified) types the expression
  -- should be applied to.
  RemVar    :: -- forall {l} (a :: TYPE (BoxedRep l))
             ModuleName -> String -> [String] -> RemoteExpr a

  -- | A reference to a value in the debuggee heap
  RemRef    :: forall {l} (a :: TYPE (BoxedRep l))
             . ForeignHValue -> RemoteExpr a

  -- | An Int literal (@Int@)
  RemInt    :: Int -> RemoteExpr Int

  -- | Apply a remote function to a remote argument to get a remote result
  --
  -- Note: the result type @b@ must have a BoxedRep!
  RemApp    :: forall {l} (a :: TYPE (BoxedRep l)) b
             . RemoteExpr (a -> b) -> RemoteExpr a -> RemoteExpr b

  -- | IO monadic bind on the remote process
  RemBindIO :: RemoteExpr (IO a) -> (RemoteExpr a -> RemoteExpr (IO b)) -> RemoteExpr (IO b)

-- | Apply a remote function to a remote argument to get a remote result
var :: -- forall {l} (a :: TYPE (BoxedRep l))
     ModuleName -> String -> [String] -> RemoteExpr a
var :: forall a. ModuleName -> String -> [String] -> RemoteExpr a
var = ModuleName -> String -> [String] -> RemoteExpr a
forall a. ModuleName -> String -> [String] -> RemoteExpr a
RemVar

-- | A reference to a value in the debuggee heap
ref :: ForeignRef a -> RemoteExpr a
ref :: forall a. ForeignRef a -> RemoteExpr a
ref = ForeignHValue -> RemoteExpr a
forall a. ForeignHValue -> RemoteExpr a
RemRef (ForeignHValue -> RemoteExpr a)
-> (ForeignRef a -> ForeignHValue) -> ForeignRef a -> RemoteExpr a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ForeignRef a -> ForeignHValue
forall a b. ForeignRef a -> ForeignRef b
castForeignRef

-- | A reference to a value in the debuggee heap
untypedRef :: forall {l} (a :: TYPE (BoxedRep l))
            . ForeignHValue -> RemoteExpr a
untypedRef :: forall a. ForeignHValue -> RemoteExpr a
untypedRef = ForeignHValue -> RemoteExpr a
forall a. ForeignHValue -> RemoteExpr a
RemRef

-- | A literal unboxed int
lit :: Int -> RemoteExpr Int
lit :: Int -> RemoteExpr Int
lit = Int -> RemoteExpr Int
RemInt

-- | A raw expression string to be parsed, compiled, and loaded onto the remote process
raw :: String -> RemoteExpr a
raw :: forall a. String -> RemoteExpr a
raw = String -> RemoteExpr a
forall a. String -> RemoteExpr a
RemRaw

-- | Apply a remote function to a remote argument to get a remote result
app :: forall {l} (a :: TYPE (BoxedRep l)) b
     . RemoteExpr (a -> b) -> RemoteExpr a -> RemoteExpr b
app :: forall a b. RemoteExpr (a -> b) -> RemoteExpr a -> RemoteExpr b
app = RemoteExpr (a -> b) -> RemoteExpr a -> RemoteExpr b
forall a b. RemoteExpr (a -> b) -> RemoteExpr a -> RemoteExpr b
RemApp

-- | Apply a remote function to a remote 'ForeignRef' to get a remote result
appRef :: RemoteExpr (a -> b) -> ForeignRef a -> RemoteExpr b
appRef :: forall a b. RemoteExpr (a -> b) -> ForeignRef a -> RemoteExpr b
appRef RemoteExpr (a -> b)
rf = RemoteExpr (a -> b) -> RemoteExpr a -> RemoteExpr b
forall a b. RemoteExpr (a -> b) -> RemoteExpr a -> RemoteExpr b
RemApp RemoteExpr (a -> b)
rf (RemoteExpr a -> RemoteExpr b)
-> (ForeignRef a -> RemoteExpr a) -> ForeignRef a -> RemoteExpr b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ForeignRef a -> RemoteExpr a
forall a. ForeignRef a -> RemoteExpr a
ref

-- | Apply a remote function after unboxing a remote int argument
-- (We need to unbox the Int on the debuggee side)
withUnboxed :: RemoteExpr Int -> (RemoteExpr (Int# -> b)) -> RemoteExpr b
withUnboxed :: forall b. RemoteExpr Int -> RemoteExpr (Int# -> b) -> RemoteExpr b
withUnboxed RemoteExpr Int
i RemoteExpr (Int# -> b)
f = (String -> RemoteExpr ((Int# -> b) -> Int -> b)
forall a. String -> RemoteExpr a
RemRaw String
"\\f i -> case i of GHC.Exts.I# i# -> f i#")
                    RemoteExpr ((Int# -> b) -> Int -> b)
-> RemoteExpr (Int# -> b) -> RemoteExpr (Int -> b)
forall a b. RemoteExpr (a -> b) -> RemoteExpr a -> RemoteExpr b
`RemApp` RemoteExpr (Int# -> b)
f RemoteExpr (Int -> b) -> RemoteExpr Int -> RemoteExpr b
forall a b. RemoteExpr (a -> b) -> RemoteExpr a -> RemoteExpr b
`RemApp` RemoteExpr Int
i

-- | IO fmap on the remote process
fmap :: (RemoteExpr a -> RemoteExpr b) -> (RemoteExpr (IO a) -> RemoteExpr (IO b))
fmap :: forall a b.
(RemoteExpr a -> RemoteExpr b)
-> RemoteExpr (IO a) -> RemoteExpr (IO b)
fmap RemoteExpr a -> RemoteExpr b
f RemoteExpr (IO a)
io_x = RemoteExpr (IO a)
io_x RemoteExpr (IO a)
-> (RemoteExpr a -> RemoteExpr (IO b)) -> RemoteExpr (IO b)
forall a b.
RemoteExpr (IO a)
-> (RemoteExpr a -> RemoteExpr (IO b)) -> RemoteExpr (IO b)
>>= \RemoteExpr a
x -> RemoteExpr b -> RemoteExpr (IO b)
forall a. RemoteExpr a -> RemoteExpr (IO a)
pure (RemoteExpr a -> RemoteExpr b
f RemoteExpr a
x)

-- | IO fmap on the remote process
(<$>) :: (RemoteExpr a -> RemoteExpr b) -> (RemoteExpr (IO a) -> RemoteExpr (IO b))
<$> :: forall a b.
(RemoteExpr a -> RemoteExpr b)
-> RemoteExpr (IO a) -> RemoteExpr (IO b)
(<$>) = (RemoteExpr a -> RemoteExpr b)
-> RemoteExpr (IO a) -> RemoteExpr (IO b)
forall a b.
(RemoteExpr a -> RemoteExpr b)
-> RemoteExpr (IO a) -> RemoteExpr (IO b)
fmap

-- | IO pure on the remote process
pure :: RemoteExpr a -> RemoteExpr (IO a)
pure :: forall a. RemoteExpr a -> RemoteExpr (IO a)
pure = RemoteExpr (a -> IO a) -> RemoteExpr a -> RemoteExpr (IO a)
forall a b. RemoteExpr (a -> b) -> RemoteExpr a -> RemoteExpr b
RemApp (ModuleName -> String -> [String] -> RemoteExpr (a -> IO a)
forall a. ModuleName -> String -> [String] -> RemoteExpr a
var (String -> ModuleName
mkModuleName String
"GHC.Base") String
"pure" [String
"IO"])

-- | IO return on the remote process
return :: RemoteExpr a -> RemoteExpr (IO a)
return :: forall a. RemoteExpr a -> RemoteExpr (IO a)
return = RemoteExpr a -> RemoteExpr (IO a)
forall a. RemoteExpr a -> RemoteExpr (IO a)
pure

-- | IO monadic bind on the remote process
(>>=) :: RemoteExpr (IO a) -> (RemoteExpr a -> RemoteExpr (IO b)) -> RemoteExpr (IO b)
>>= :: forall a b.
RemoteExpr (IO a)
-> (RemoteExpr a -> RemoteExpr (IO b)) -> RemoteExpr (IO b)
(>>=) = RemoteExpr (IO a)
-> (RemoteExpr a -> RemoteExpr (IO b)) -> RemoteExpr (IO b)
forall a b.
RemoteExpr (IO a)
-> (RemoteExpr a -> RemoteExpr (IO b)) -> RemoteExpr (IO b)
RemBindIO

-- | IO monadic bind on the remote process
(>>) :: RemoteExpr (IO a) -> RemoteExpr (IO b) -> RemoteExpr (IO b)
>> :: forall a b.
RemoteExpr (IO a) -> RemoteExpr (IO b) -> RemoteExpr (IO b)
(>>) RemoteExpr (IO a)
ma RemoteExpr (IO b)
mb = RemoteExpr (IO b -> IO b) -> RemoteExpr (IO b) -> RemoteExpr (IO b)
forall a b. RemoteExpr (a -> b) -> RemoteExpr a -> RemoteExpr b
app (RemoteExpr (IO a -> IO b -> IO b)
-> RemoteExpr (IO a) -> RemoteExpr (IO b -> IO b)
forall a b. RemoteExpr (a -> b) -> RemoteExpr a -> RemoteExpr b
app RemoteExpr (IO a -> IO b -> IO b)
forall a b. RemoteExpr (IO a -> IO b -> IO b)
andThen RemoteExpr (IO a)
ma) RemoteExpr (IO b)
mb
  where
    andThen :: RemoteExpr (IO a -> IO b -> IO b)
    andThen :: forall a b. RemoteExpr (IO a -> IO b -> IO b)
andThen = ModuleName
-> String -> [String] -> RemoteExpr (IO a -> IO b -> IO b)
forall a. ModuleName -> String -> [String] -> RemoteExpr a
var (String -> ModuleName
mkModuleName String
"GHC.Base") String
">>" [String
"IO"]

--------------------------------------------------------------------------------
-- * Evaluation of 'RemoteExprs' (higher level)
--------------------------------------------------------------------------------

-- | Evaluate a @a@ expression on the remote process and return the foreign
-- reference to the result.
eval :: RemoteExpr a -> Debugger (Either BadEvalStatus (ForeignRef a))
eval :: forall a.
RemoteExpr a -> Debugger (Either BadEvalStatus (ForeignRef a))
eval RemoteExpr a
expr = RemoteExpr (IO a) -> Debugger (Either BadEvalStatus (ForeignRef a))
forall a.
RemoteExpr (IO a) -> Debugger (Either BadEvalStatus (ForeignRef a))
evalIO (RemoteExpr a -> RemoteExpr (IO a)
forall a. RemoteExpr a -> RemoteExpr (IO a)
pure RemoteExpr a
expr)

-- | Run an @IO a@ computation in the remote process and return the foreign
-- reference to the returned @a@
evalIO :: RemoteExpr (IO a) -> Debugger (Either BadEvalStatus (ForeignRef a))
evalIO :: forall a.
RemoteExpr (IO a) -> Debugger (Either BadEvalStatus (ForeignRef a))
evalIO RemoteExpr (IO a)
expr = do
  r <- RemoteExpr (IO [a])
-> Debugger (Either BadEvalStatus [ForeignRef a])
forall a.
RemoteExpr (IO [a])
-> Debugger (Either BadEvalStatus [ForeignRef a])
evalIOList ((RemoteExpr a -> RemoteExpr [a])
-> RemoteExpr (IO a) -> RemoteExpr (IO [a])
forall a b.
(RemoteExpr a -> RemoteExpr b)
-> RemoteExpr (IO a) -> RemoteExpr (IO b)
fmap RemoteExpr a -> RemoteExpr [a]
forall a. RemoteExpr a -> RemoteExpr [a]
singletonList RemoteExpr (IO a)
expr)
  case r of
    Left BadEvalStatus
e    -> Either BadEvalStatus (ForeignRef a)
-> Debugger (Either BadEvalStatus (ForeignRef a))
forall a. a -> Debugger a
forall (m :: * -> *) a. Monad m => a -> m a
Prelude.return (BadEvalStatus -> Either BadEvalStatus (ForeignRef a)
forall a b. a -> Either a b
Left BadEvalStatus
e)
    Right [ForeignRef a
x] -> Either BadEvalStatus (ForeignRef a)
-> Debugger (Either BadEvalStatus (ForeignRef a))
forall a. a -> Debugger a
forall (m :: * -> *) a. Monad m => a -> m a
Prelude.return (ForeignRef a -> Either BadEvalStatus (ForeignRef a)
forall a b. b -> Either a b
Right ForeignRef a
x)
    Right []  -> Either BadEvalStatus (ForeignRef a)
-> Debugger (Either BadEvalStatus (ForeignRef a))
forall a. a -> Debugger a
forall (m :: * -> *) a. Monad m => a -> m a
Prelude.return (BadEvalStatus -> Either BadEvalStatus (ForeignRef a)
forall a b. a -> Either a b
Left BadEvalStatus
EvalReturnedNoResults)
    Right [ForeignRef a]
_   -> Either BadEvalStatus (ForeignRef a)
-> Debugger (Either BadEvalStatus (ForeignRef a))
forall a. a -> Debugger a
forall (m :: * -> *) a. Monad m => a -> m a
Prelude.return (BadEvalStatus -> Either BadEvalStatus (ForeignRef a)
forall a b. a -> Either a b
Left BadEvalStatus
EvalReturnedTooManyResults)

-- | Evaluate a string expression on the remote process and return the string
-- to the debugger
evalString :: RemoteExpr String -> Debugger (Either BadEvalStatus String)
evalString :: RemoteExpr String -> Debugger (Either BadEvalStatus String)
evalString RemoteExpr String
expr = RemoteExpr (IO String) -> Debugger (Either BadEvalStatus String)
evalIOString (RemoteExpr String -> RemoteExpr (IO String)
forall a. RemoteExpr a -> RemoteExpr (IO a)
pure RemoteExpr String
expr)

{- |
Evaluate a 'RemoteExpr' for a remote @IO [a]@ and return a list of
'ForeignHValue' with one element per returned @a@.

=== __Example__

@
Remote.evalIOList $ Remote.do
  clonedStack <- Remote.cloneThreadStack `Remote.appRef` threadIdRef
  frames      <- Remote.decodeStack      `Remote.app`    clonedStack
  return (Remote.ssc_stack `Remote.app` frames)
@
-}
evalIOList :: RemoteExpr (IO [a]) -> Debugger (Either BadEvalStatus [ForeignRef a])
evalIOList :: forall a.
RemoteExpr (IO [a])
-> Debugger (Either BadEvalStatus [ForeignRef a])
evalIOList RemoteExpr (IO [a])
expr = ExceptT BadEvalStatus Debugger [ForeignRef a]
-> Debugger (Either BadEvalStatus [ForeignRef a])
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (ExceptT BadEvalStatus Debugger [ForeignRef a]
 -> Debugger (Either BadEvalStatus [ForeignRef a]))
-> ExceptT BadEvalStatus Debugger [ForeignRef a]
-> Debugger (Either BadEvalStatus [ForeignRef a])
forall a b. (a -> b) -> a -> b
$ do
  res_fv <- RemoteExpr (IO [a])
-> ExceptT BadEvalStatus Debugger (ForeignRef (IO [a]))
forall a.
RemoteExpr a -> ExceptT BadEvalStatus Debugger (ForeignRef a)
debuggeeEval RemoteExpr (IO [a])
expr

  r <- lift $ Raw.evalExpr (EvalThis (castForeignRef res_fv))
  liftEither (map castForeignRef Prelude.<$> r)

-- | Execute an @IO String@ on the remote process and serialize the string back to the debugger.
evalIOString :: RemoteExpr (IO String) -> Debugger (Either BadEvalStatus String)
evalIOString :: RemoteExpr (IO String) -> Debugger (Either BadEvalStatus String)
evalIOString RemoteExpr (IO String)
expr = ExceptT BadEvalStatus Debugger String
-> Debugger (Either BadEvalStatus String)
forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT (ExceptT BadEvalStatus Debugger String
 -> Debugger (Either BadEvalStatus String))
-> ExceptT BadEvalStatus Debugger String
-> Debugger (Either BadEvalStatus String)
forall a b. (a -> b) -> a -> b
$ do
  res_fv <- RemoteExpr (IO String)
-> ExceptT BadEvalStatus Debugger (ForeignRef (IO String))
forall a.
RemoteExpr a -> ExceptT BadEvalStatus Debugger (ForeignRef a)
debuggeeEval RemoteExpr (IO String)
expr
  lift $ Raw.evalString res_fv

--------------------------------------------------------------------------------
-- ** Recursive evaluation of 'RemoteExpr' (lower-level)
--------------------------------------------------------------------------------

-- | Get the foreign reference to a heap value of type @a@ in the debuggee
-- process from the given remote expr.
--
-- The result can't be (@ForeignRef a@) because of levity polymorphism, so we
-- return the untyped foreign ref.
debuggeeEval :: RemoteExpr a -> ExceptT BadEvalStatus Debugger (ForeignRef a)
debuggeeEval :: forall a.
RemoteExpr a -> ExceptT BadEvalStatus Debugger (ForeignRef a)
debuggeeEval RemoteExpr a
expr = do
    eval_expr <- RemoteExpr (IO [a])
-> ExceptT BadEvalStatus Debugger (EvalExpr ForeignHValue)
forall a'.
RemoteExpr a'
-> ExceptT BadEvalStatus Debugger (EvalExpr ForeignHValue)
go (RemoteExpr [a] -> RemoteExpr (IO [a])
forall a. RemoteExpr a -> RemoteExpr (IO a)
pure (RemoteExpr a -> RemoteExpr [a]
forall a. RemoteExpr a -> RemoteExpr [a]
singletonList RemoteExpr a
expr))
    r <- lift $ handleSingStatus Prelude.<$> Raw.evalExpr eval_expr
    liftEither (castForeignRef Prelude.<$> r)
  where

    -- Construct the largest possible EvalExpr and then evaluate it all at once.
    -- When we find an IO action we execute it.
    go :: forall {l'} (a' :: TYPE (BoxedRep l'))
        . RemoteExpr a' -> ExceptT BadEvalStatus Debugger (EvalExpr ForeignHValue)
    go :: forall a'.
RemoteExpr a'
-> ExceptT BadEvalStatus Debugger (EvalExpr ForeignHValue)
go = \case
      RemRaw String
s -> do
        fhv <- Debugger ForeignHValue
-> ExceptT BadEvalStatus Debugger ForeignHValue
forall (m :: * -> *) a. Monad m => m a -> ExceptT BadEvalStatus m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Debugger ForeignHValue
 -> ExceptT BadEvalStatus Debugger ForeignHValue)
-> Debugger ForeignHValue
-> ExceptT BadEvalStatus Debugger ForeignHValue
forall a b. (a -> b) -> a -> b
$ String -> Debugger ForeignHValue
compileRaw String
s
        Prelude.return (EvalThis fhv)
      RemVar ModuleName
mod_name String
var_name [String]
ty_args -> do
        fhv <- Debugger ForeignHValue
-> ExceptT BadEvalStatus Debugger ForeignHValue
forall (m :: * -> *) a. Monad m => m a -> ExceptT BadEvalStatus m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (Debugger ForeignHValue
 -> ExceptT BadEvalStatus Debugger ForeignHValue)
-> Debugger ForeignHValue
-> ExceptT BadEvalStatus Debugger ForeignHValue
forall a b. (a -> b) -> a -> b
$ ModuleName -> String -> [String] -> Debugger ForeignHValue
compileVar ModuleName
mod_name String
var_name [String]
ty_args
        Prelude.return (EvalThis fhv)
      RemRef ForeignHValue
r -> EvalExpr ForeignHValue
-> ExceptT BadEvalStatus Debugger (EvalExpr ForeignHValue)
forall a. a -> ExceptT BadEvalStatus Debugger a
forall (m :: * -> *) a. Monad m => a -> m a
Prelude.return (ForeignHValue -> EvalExpr ForeignHValue
forall a. a -> EvalExpr a
EvalThis ForeignHValue
r)
      RemInt Int
i ->
        -- todo: interpreter message for unboxed literals
        -- TODO: lookup in the cache if we loaded this int already.
        ForeignHValue -> EvalExpr ForeignHValue
forall a. a -> EvalExpr a
EvalThis (ForeignHValue -> EvalExpr ForeignHValue)
-> ExceptT BadEvalStatus Debugger ForeignHValue
-> ExceptT BadEvalStatus Debugger (EvalExpr ForeignHValue)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
Prelude.<$> Debugger ForeignHValue
-> ExceptT BadEvalStatus Debugger ForeignHValue
forall (m :: * -> *) a. Monad m => m a -> ExceptT BadEvalStatus m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift (String -> Debugger ForeignHValue
compileRaw (Int -> String
forall a. Show a => a -> String
show Int
i String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
":: Int"))
      RemApp RemoteExpr (a -> b)
f RemoteExpr a
arg -> do
        arg_e <- RemoteExpr a
-> ExceptT BadEvalStatus Debugger (EvalExpr ForeignHValue)
forall a'.
RemoteExpr a'
-> ExceptT BadEvalStatus Debugger (EvalExpr ForeignHValue)
go RemoteExpr a
arg
        f_e   <- go f
        Prelude.return (f_e `EvalApp` arg_e)
      RemBindIO RemoteExpr (IO a)
iox RemoteExpr a -> RemoteExpr (IO b)
k -> do

        expr_arg_io_fv <- RemoteExpr (IO [a])
-> ExceptT BadEvalStatus Debugger (EvalExpr ForeignHValue)
forall a'.
RemoteExpr a'
-> ExceptT BadEvalStatus Debugger (EvalExpr ForeignHValue)
go (RemoteExpr (a -> [a]) -> RemoteExpr (IO a) -> RemoteExpr (IO [a])
forall a b.
RemoteExpr (a -> b) -> RemoteExpr (IO a) -> RemoteExpr (IO b)
fmapIO RemoteExpr (a -> [a])
forall a. RemoteExpr (a -> [a])
singletonListVar RemoteExpr (IO a)
iox)

        e_arg_fv <- lift $ handleSingStatus Prelude.<$> Raw.evalExpr expr_arg_io_fv
        arg_fv   <- liftEither (castForeignRef Prelude.<$> e_arg_fv)
        go (k (ref arg_fv))

instance Show (RemoteExpr (a :: TYPE (BoxedRep l))) where
  show :: RemoteExpr a -> String
show (RemRaw String
s) = String
"(" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
s String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"
  show (RemVar ModuleName
mod_name String
var_name [String]
ty_args) =
    String
"(" String -> String -> String
forall a. [a] -> [a] -> [a]
++ ModuleName -> String
moduleNameString ModuleName
mod_name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"." String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
var_name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ (if [String] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [String]
ty_args then String
"" else String
" ")
        String -> String -> String
forall a. [a] -> [a] -> [a]
++ [String] -> String
unwords ((String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (Char
'@'Char -> String -> String
forall a. a -> [a] -> [a]
:) [String]
ty_args)
  show (RemRef ForeignHValue
_) = String
"<foreign ref>"
  show (RemInt Int
i) = Int -> String
forall a. Show a => a -> String
show Int
i
  show (RemApp RemoteExpr (a -> b)
f RemoteExpr a
arg) =
    String
"(" String -> String -> String
forall a. [a] -> [a] -> [a]
++ RemoteExpr (a -> b) -> String
forall a. Show a => a -> String
show RemoteExpr (a -> b)
f String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" " String -> String -> String
forall a. [a] -> [a] -> [a]
++ RemoteExpr a -> String
forall a. Show a => a -> String
show RemoteExpr a
arg String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"
  show (RemBindIO RemoteExpr (IO a)
iox RemoteExpr a -> RemoteExpr (IO b)
k) =
    let k_str :: RemoteExpr (IO b)
k_str = RemoteExpr a -> RemoteExpr (IO b)
k (ModuleName -> String -> [String] -> RemoteExpr a
forall a. ModuleName -> String -> [String] -> RemoteExpr a
var (String -> ModuleName
mkModuleName String
"Dummy") String
"dummy" [])
     in RemoteExpr (IO a) -> String
forall a. Show a => a -> String
show RemoteExpr (IO a)
iox String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
">>= (\\dummy -> " String -> String -> String
forall a. [a] -> [a] -> [a]
++ RemoteExpr (IO b) -> String
forall a. Show a => a -> String
show RemoteExpr (IO b)
k_str String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
")"

--------------------------------------------------------------------------------
-- ** Builtins that are needed here too.

-- | Remote 'Data.List.singleton' (applied)
singletonList :: RemoteExpr a -> RemoteExpr [a]
singletonList :: forall a. RemoteExpr a -> RemoteExpr [a]
singletonList = RemoteExpr (a -> [a]) -> RemoteExpr a -> RemoteExpr [a]
forall a b. RemoteExpr (a -> b) -> RemoteExpr a -> RemoteExpr b
app RemoteExpr (a -> [a])
forall a. RemoteExpr (a -> [a])
singletonListVar

-- | Remote 'Data.List.singleton'
singletonListVar :: RemoteExpr (a -> [a])
singletonListVar :: forall a. RemoteExpr (a -> [a])
singletonListVar = ModuleName -> String -> [String] -> RemoteExpr (a -> [a])
forall a. ModuleName -> String -> [String] -> RemoteExpr a
var (String -> ModuleName
mkModuleName String
"Data.List") String
"singleton" []

-- | Remote 'fmap' for IO. Only works with @RemoteExpr (a -> b)@, not
-- @RemoteExpr a -> RemoteExpr b@ (unlike 'fmap').
--
-- We need it to avoid defining the evaluator for @RemBindIO@ in terms of
-- itself.
fmapIO :: RemoteExpr (a -> b) -> RemoteExpr (IO a) -> RemoteExpr (IO b)
fmapIO :: forall a b.
RemoteExpr (a -> b) -> RemoteExpr (IO a) -> RemoteExpr (IO b)
fmapIO = RemoteExpr (IO a -> IO b) -> RemoteExpr (IO a) -> RemoteExpr (IO b)
forall a b. RemoteExpr (a -> b) -> RemoteExpr a -> RemoteExpr b
app (RemoteExpr (IO a -> IO b)
 -> RemoteExpr (IO a) -> RemoteExpr (IO b))
-> (RemoteExpr (a -> b) -> RemoteExpr (IO a -> IO b))
-> RemoteExpr (a -> b)
-> RemoteExpr (IO a)
-> RemoteExpr (IO b)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. RemoteExpr ((a -> b) -> IO a -> IO b)
-> RemoteExpr (a -> b) -> RemoteExpr (IO a -> IO b)
forall a b. RemoteExpr (a -> b) -> RemoteExpr a -> RemoteExpr b
app (ModuleName
-> String -> [String] -> RemoteExpr ((a -> b) -> IO a -> IO b)
forall a. ModuleName -> String -> [String] -> RemoteExpr a
var (String -> ModuleName
mkModuleName String
"Data.Functor") String
"fmap" [String
"IO"])