id x = xThis function might seem useless at first glance, but it can be very useful in a higher order context.
>>> length $ filter id [True, True, False, True] 3
>>> Just (Just 3) >>= id Just 3
>>> foldr id 0 [(^3), (*5), (+2)] 1000
par :: a -> b -> b par x y = case (par# x) of _ -> lazy yIf lazy were not lazy, par would look strict in y which would defeat the whole purpose of par.
id x = x
case x of A -> 3 * y B -> x * xto
let f_arg0 = case x of {A -> 3; _ -> x} f_arg1 = case x of {A -> y; _ -> x} f_out = f_arg0 * f_arg1 in case x of A -> f_out B -> f_outHowever, it won't do this for:
case x of A -> 3 + y B -> x + xBecause according to the internal heuristics the multiplexer introduced for the deduplication are more expensive than the addition. This might not be the case for your particular platform. In these cases you can force Clash to deduplicate by:
case x of A -> deDup (3 + y) B -> deDup (x + x)
case x of A -> f 3 y B -> f x x C -> h xto
let f_arg0 = case x of {A -> 3; _ -> x} f_arg1 = case x of {A -> y; _ -> x} f_out = f f_arg0 f_arg1 in case x of A -> f_out B -> f_out C -> h xi.e. it deduplicates functions (and operators such as multiplication) between case-alternatives to save on area. This comes at the cost of multiplexing the arguments for the deduplicated function. There are two reasons you would want to stop Clash from doing this:
case x of A -> noDeDup f 3 y B -> f x x C -> h xWhere the application of f in the A-alternative is now explicitly not deduplicated, and given that the f in the B-alternative is the only remaining application of f in the case-expression it is also not deduplicated. Note that if the C-alternative also had an application of f, then the applications of f in the B- and C-alternatives would have been deduplicated; i.e. the final circuit would have had two application of f.
f a b = ... pack a ... pack b ...Where it is basically an error if either a or b ever throws an XException, and so you want that to be reported the moment a or b is used, instead of it being thrown when evaluating the result of f, then do:
{-# LANGUAGE ViewPatterns #-} f (xToError -> a) (xToError -> b) = ...Unlike xToErrorCtx, where we have an extra String argument to distinguish one call to xToError to the other, xToError will use the CallStack mechanism to aid the user in distinguishing different call to xToError. We can also use BangPatterns to report the potential XException being thrown by a or b even earlier, i.e. when f is applied:
{-# LANGUAGE ViewPatterns, BangPatterns #-} f (xToError -> !a) (xToError -> !b) = ...NB: Fully synthesizable, so doesn't have to be removed before synthesis
>>> :set -XViewPatterns -XDataKinds >>> import Clash.Sized.BitVector >>> import GHC.Stack >>> :{ let f, g, h, h' :: HasCallStack => Bit -> BitVector 8 -> BitVector 8 f = g g = h h (xToError -> a) (xToError -> b) = slice d7 d0 (pack a ++# b) h' a b = slice d7 d0 (pack a ++# b) :}
>>> h' (errorX "QQ") 3 0b0000_0011 >>> f (errorX "QQ") 3 *** Exception: CallStack (from HasCallStack): xToError, called at ... h, called at ... g, called at ... f, called at ... X: QQ CallStack (from HasCallStack): errorX, called at ...