[Haskell-cafe] How to avoid CPP (Was: Monad of no `return` Proposal (MRP): Moving `return` out of `Monad`)

Henning Thielemann lemming at henning-thielemann.de
Sun Oct 18 18:49:58 UTC 2015


On Mon, 5 Oct 2015, Gregory Collins wrote:

> Um, no, it usually isn't anything like that. Here's a sampling of some of the things I've used CPP for in the past few
> years:
>  *  After GHC 7.4, when using a newtype in FFI imports you need to import the constructor, i.e. "import
>     Foreign.C.Types(CInt(..))" --- afaik CPP is the only way to shut up warnings everywhere

I import them qualified and then define

    type CInt = CTypes.CInt

sometimes.

>  *  defaultTimeLocale moved from System.Locale to Data.Time.Format in time-1.5 (no compat package for this, afaik)

I was advised to always import time-1.5.

>  *  one of many various changes to Typeable in the GHC 7.* series (deriving works better now, mkTyCon vs mkTyCon3, etc)

I have not used that. Like I have not used the ever changing Template 
Haskell stuff.

>  *  Do I have to hide "catch" from Prelude, or not? It got moved, and "hiding" gives an error if the symbol you're trying
>     to hide is missing. Time to break out the CPP (and curse myself for not just using the qualified import in the first
>     place)

I think System.IO.Error.catchIOError maintains the old behaviour.

>  *  Do I get monoid functions from Prelude or from Data.Monoid? Same w/ Applicative, Foldable, Word. I don't know where
>     anything is supposed to live anymore, or which sequence of imports will shut up spurious warnings on all four versions
>     of GHC I support, so the lowest-friction fix is: break out the #ifdef spackle

I always import them from the most specific module. Where GHC-7.10 Prelude 
causes conflicts I even started to import more basic Prelude stuff from 
modules like Data.Bool, Data.Eq and friends. Horrible, but works without 
CPP.

>  *  ==# and friends return Int# instead of Bool after GHC 7.8.1

I did not use it. I have also warned that the change might not be a good 
idea since LLVM knows that its 'i1' type can only have the values 0 and 1 
and it does not know that for 'i32' or 'i64'.

>  *  To use functions like "tryReadMVar", "unsafeShiftR", and "atomicModifyIORef'" that are in recent base versions but not
>     older ones (this is a place where CPP use is actually justified)

I have not used them so far.


I have solved more complicated cases with conditional Hs-Source-Dirs:
    http://wiki.haskell.org/Cabal/Developer-FAQ#Adapt_to_different_systems_without_CPP

It's cumbersome but so far I managed most transitions without CPP.

(Nonetheless, MRP would require the complicated Hs-Source-Dirs solution 
for far too many packages.)


More information about the Haskell-Cafe mailing list