1

I want to create a human readable DSL which non-haskell programmer could understand for creating specifications for black-box testing of external systems.

And I wonder if something like this is possible to do in Haskell.

action = readProcess "sleep 1; print success"

prop_action = monadicIO $
    within 100000 >>=
    repliesWith (== "success")

within :: Int -> IO a -> IO
within t = fromMaybe False $ timeout t

repliesWith :: (a -> Bool) -> IO a -> IO Bool
repliesWith v = liftM v

Here I'm giving a pseudo code for checking that action would return value "success" within 0.1 seconds. It seems like I need some kind of monad that would short-circuit on false values to chain multiple checks that pass values from one to another.

Feel like something like this should exist. Maybe you can suggest a library or how to implement my idea in Haskell.

user1685095
  • 5,787
  • 9
  • 51
  • 100
  • Possible to do yes, but your syntax is off. You want `within x yourAction`, not `within x >>= yourAction`. `within` could then be easily implemented with a fork and a time out. – Cubic Sep 12 '17 at 15:07
  • The idea is to chain checks, not to create and hoc `within` check. For example one could imagine `before` condition that states that next action should happen before another parallel action and if it is then pass result to another check. And there's no need to fork I believe. `Control.Concurrent.timeout` already does the thing I need. – user1685095 Sep 12 '17 at 16:19
  • That's because `timeout` does the forking for you; I didn't mean you had to use `forkIO` specifically. – Cubic Sep 12 '17 at 18:30
  • @Cubic Yeah okay. My question is still unanswered though. Can I create kind of compound monadic properties? The point of the DSL to be readable to a non haskell programmer. It's okay If I can't I just want to know for sure. – user1685095 Sep 12 '17 at 19:14
  • The exact thing you wrote works just fine if you change the type of `within` to `within :: Int -> IO Bool -> IO Bool` and `monadicIO $ within 100000 >>= repliesWith (=="success")` to `monadicIO . within 100000 . repliesWith (=="success") $ theActionYouWantToTest`. If you want something beyond that you'll have to elaborate. – Cubic Sep 12 '17 at 20:51
  • @user1685095, not quite sure what you mean by "compound monadic properties", but probably. `before` is certainly implementable. I think you can do everything you need in a `ExceptT TestFailure IO` context, let's call it `Test`. I think the design would be more like `repliesWith :: (a -> Bool) -> Test a -> Test ()` though -- you raise an exception when it fails, rather than returning `False`. – luqui Sep 12 '17 at 21:38
  • @luqui Yeah, I thought about types for a while and came to a conclustion that I would just need a monad transformer `EitherT` inside `IO` monad. I still not sure if the whole idea of writing spec in a human readable form is feasible, but the problem I have right now is that I don't know how to make human readable reports the way `hspec` does. – user1685095 Sep 14 '17 at 13:39
  • @user1685095 my own experience with DSLs like this is you can't expect people not to have to learn anything about Haskell, but they don't need to be gurus. But the more "syntax magic" games you play in the name of "readability", the harder it is (because all those games come with weird corner cases) -- just be as direct as you can. – luqui Sep 15 '17 at 00:08
  • @luqui I'm very skeptical about this idea myself. It's just would be very nice to have a documentation that can be used for testing. Right now people do double work basically. I'm talking about system specification, not just function docs. – user1685095 Sep 15 '17 at 10:00

0 Answers0