Oh, get rid of all these conventions. You have many related settings that in one context will have one set of values, in another context a different set.
data TabConfig = TabConfig { tabX, tabY, tabWidth, tabHeight :: Int, tabPosition :: Position, tabMargin :: Margin }
(You do not need to use the syntax of the entry, I do this for clarity)
Now you just need to provide your functions with the appropriate TabConfig , from which they can extract values. You can provide the defaultConfig function ...
defaultConfig :: Context -> TabConfig defaultConfig c = TabConfig { 5, 3, 20, (pageHeight c) - 80, Position left bottom, Margin 3 0 }
You can also have
bottomConfig :: Context -> TabConfig bottomConfig c = TabConfig { 3, 60, (pageX c) - 60, 20, Position left top, Margin 0 3 }
Then you simply specify the appropriate TabConfig in the appropriate context. (I hope you found out that Context is a different type of recording style, and of course you can play with the same tricks).
If more parameters are added to TabConfig, and only a few are at the bottom, you can do
bottomConfig c = let def = defaultConfig c in def { tabX = 3, tabY = 60, ...
Just create the correct configuration for the current context and make it available to your functions. Why should your table-drawing functions need to know about the logic you use to determine how their position on a page limits their size? What happens when new conditions impose additional restrictions? Mixing them up is terrible. Separation of problems is at least as important for functional programming as it is in OO. TO
Of course, I'm trying to hint that you need a Reader monad. But the reader monad is so simple that you don't need to know that you use it if the monads are still discouraged.