Description
Branch on whether a constraint is satisfied.
Description
This library provides a mechanism that can be used to branch on whether a constraint is satisfied (not limited to typeclass instances).
Usage example:
{-# OPTIONS_GHC -fplugin=IfSat.Plugin #-}
module MyModule where
import Data.Constraint.If ( IfSat(ifSat) )
hypot :: forall a. ( Floating a, IfSat (FMA a) ) => a -> a -> a
hypot = ifSat @(FMA a) withFMA withoutFMA
where
withFMA :: FMA a => a -> a -> a
withFMA x y =
let
h = sqrt $ fma x x (y * y)
h² = h * h
x² = x * x
u = fma (-y) y (h² - x²) + fma h h (-h²) - fma x x (-x²)
in
h - u / ( 2 * h )
withoutFMA :: a -> a -> a
withoutFMA x y = sqrt ( x * x + y * y )
Here we select between two ways of computing the hypotenuse function based on whether we have access to the fused multiply-add operation
fma :: FMA a => a -> a -> a -> a
which computes \ x y z -> ( x * y ) + z
in a single instruction, providing stronger guarantees about precision of the result.
A call of the form hypot @MyNumberType
will either use the robust withFMA
function when an FMA MyNumberType
instance is available, or will fallback to the simple withoutFMA
implementation when no such instance can be found.