callstack - How to add `HasCallStack` to a custom monad in Haskell? - Stack Overflow

I can use a type alias to add HasCallStack to a monad e.g.:type XIO' a = HasCallStack => IO aw

I can use a type alias to add HasCallStack to a monad e.g.:

type XIO' a = HasCallStack => IO a

which saves me some keystrokes and I don't have to remember about putting HasCallStack everywhere.

However, when I define a custom datatype like that:

data XIO a = HasCallStack => XIO { unXIO :: IO a }

The call stacks aren't added to functions of type XIO. Is there a way to add a HasCallStack constraint automatically to a custom monad? I've also tried adding it to all functions in the instances using InstanceSigs but it made no difference. A full example:

module Main (main) where

import RIO

main :: IO ()
main = do
  catchAny (unXIO $ f1) $ \ex -> do
    putStrLn "::: An exception without callstack"
    putStrLn $ displayException ex

  catchAny (f1') $ \ex -> do
    putStrLn "::: An exception with callstack"
    putStrLn $ displayException ex

f1' :: XIO' ()
f1' = do
  pure ()
  f2'
  pure ()

f1 :: XIO ()
f1 = do
  pure ()
  f2
  pure ()

f2' :: XIO' ()
f2' = do
  pure ()
  _ <- throwIO $ stringException "Hello"
  pure ()

f2 :: XIO ()
f2 = do
  pure ()
  _ <- throwIO $ stringException "Hello"
  pure ()

type XIO' a = HasCallStack => IO a

data XIO a = HasCallStack => XIO { unXIO :: IO a }

instance Functor XIO where
  fmap f (XIO m) = XIO $ fmap f m

instance Applicative XIO where
  pure a = XIO $ pure a
  XIO f <*> XIO a = XIO $ f <*> a

instance Monad XIO where
  return = pure
  XIO m >>= f = XIO $ m >>= (\k -> unXIO $ f k)

instance MonadIO XIO where
  liftIO m = XIO $ m

I can use a type alias to add HasCallStack to a monad e.g.:

type XIO' a = HasCallStack => IO a

which saves me some keystrokes and I don't have to remember about putting HasCallStack everywhere.

However, when I define a custom datatype like that:

data XIO a = HasCallStack => XIO { unXIO :: IO a }

The call stacks aren't added to functions of type XIO. Is there a way to add a HasCallStack constraint automatically to a custom monad? I've also tried adding it to all functions in the instances using InstanceSigs but it made no difference. A full example:

module Main (main) where

import RIO

main :: IO ()
main = do
  catchAny (unXIO $ f1) $ \ex -> do
    putStrLn "::: An exception without callstack"
    putStrLn $ displayException ex

  catchAny (f1') $ \ex -> do
    putStrLn "::: An exception with callstack"
    putStrLn $ displayException ex

f1' :: XIO' ()
f1' = do
  pure ()
  f2'
  pure ()

f1 :: XIO ()
f1 = do
  pure ()
  f2
  pure ()

f2' :: XIO' ()
f2' = do
  pure ()
  _ <- throwIO $ stringException "Hello"
  pure ()

f2 :: XIO ()
f2 = do
  pure ()
  _ <- throwIO $ stringException "Hello"
  pure ()

type XIO' a = HasCallStack => IO a

data XIO a = HasCallStack => XIO { unXIO :: IO a }

instance Functor XIO where
  fmap f (XIO m) = XIO $ fmap f m

instance Applicative XIO where
  pure a = XIO $ pure a
  XIO f <*> XIO a = XIO $ f <*> a

instance Monad XIO where
  return = pure
  XIO m >>= f = XIO $ m >>= (\k -> unXIO $ f k)

instance MonadIO XIO where
  liftIO m = XIO $ m
Share asked Mar 3 at 20:23 carbolymercarbolymer 1,6522 gold badges17 silver badges32 bronze badges 1
  • 1 Note that, even if it were possible, those HasCallStacks could likely cause memory leaks for code that recurses a lot. – danidiaz Commented Mar 3 at 20:30
Add a comment  | 

1 Answer 1

Reset to default 1

I can't think of a way to associate the HasCallStack constraint with a data type. Because of the way it's implemented, I think it needs to be part of each function signature that should contribute to the call stack, either specified directly or as part of a type alias.

So, your best bet is to define your custom monad as an internal type and then define a type alias for use in function signatures, like:

newtype XIO_internal a = XIO { unXIO :: IO a }
type XIO a = HasCallStack => XIO_internal a

For example:

import RIO

newtype XIO_internal a = XIO { unXIO :: IO a }
  deriving (Functor, Applicative, Monad, MonadIO)
type XIO a = HasCallStack => XIO_internal a

main :: IO ()
main = do
  catchAny (unXIO $ f1 2) $ \ex -> do
    putStrLn $ displayException ex

f1 :: Int -> XIO ()
f1 x = do
  f2 (x*2)

f2 :: Int -> XIO ()
f2 x = do
  liftIO $ print x
  _ <- throwIO $ stringException "Hello"
  pure ()

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1745073572a4609700.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信