Working on a project consisting as building a simple language interpreter, Haskell was choosen because of his functonnality.

My issue is the following. I have a lot of function (& pattern match inside those functions) that actually compute something. I would like to print on screen one parameter (of type Context) at each function application for all my functions.

2 Answers
2

Typically the idea of printing something between each evaluation is considered inelegant in Haskell. It interweaves pure and effectful computations in a way that makes it much more difficult to reason about your code. It's also not nearly as deterministic as you might expect coming from strict languages: laziness means that your print statements inside pure code may get evaluated multiple times, or not at all, without warning.

The natural solution to this is to execute things in a sequencing Monad. Writer is a fairly pure Monad which would allow you to "print" your ctx to a buffer and then actually write that buffer out at a later stage. Laziness will actually make the buffering and writing out come together so as to make that appear seamless.

The other option is to lift your computation into the IO monad and have both complete sequencing and access to all effects. It looks like your computation involves recursing through an AST of some kind---you can return monadic actions like IO Int instead of their pure cousins Int from each recursive call and in that way build an impure computation as your traverse your tree.

The final thing to look into if you only need to print the ctx for debugging purposes is the Debug.Trace module which does include methods for printing impurely in the middle of pure code. It's a bad decision to include these functions in production code, though.

What you want to do can be described as aspect-oriented programming, or (generalising further) as metaprogramming. Haskell does offer a metaprogramming facility, called Template Haskell, so that would be one way to do it.

However, there might be a simpler way, if you have several functions of the same type. Then you can put them in a list and do

map (\f y ctx -> printAndExec ctx $ f y ctx) list

But then you would have to assign elements of the list to function names, which is not so elegant.