开发者

Haskell multiple statement efficiency

开发者 https://www.devze.com 2023-03-28 12:34 出处:网络
Is this efficient for checking multiple statements in Haskell? Or this there a better way? case ((x > -10) && (x < 20),x /= 9,(x `mod` 2) == 0,x) of

Is this efficient for checking multiple statements in Haskell? Or this there a better way?

case ((x > -10) && (x < 20),x /= 9,(x `mod` 2) == 0,x) of 
    (False,_,_,_) -> error "Not in range"
    (_,False,_,_) -> error "Must not be 9"
    (_,_,False,_) -> error "Must be even"
    (True,True,Tru开发者_开发百科e,10) -> stuff ()
    (True,True,True,20) -> stuff ()
    _ -> error "Error Message"


It's sometimes difficult to come up with small examples of this problem which don't look contrived, but they do happen. Sometimes you need a bunch of computed results to figure out how to split a function into its cases.

So yes, I often find it's cleanest to use case on a tuple of things-I-might-care-about to build complex decision processes. I trust laziness to compute the minimum required to resolve which branch to invoke.

It's worth trying to express your tests via Boolean guards (or even pattern guards), but sometimes there's nothing to beat tabulating the computed values you need in a big tuple and then writing a row for each interesting combination of circumstances.


Assuming that caring about efficiency is really important, and is not premature optimization, you should optimize for the case which is most common; I think that even in Haskell, it means that you want to have the True,True,True cases on top.

Actually, in the given case, if x == 10 or x == 20 you don't need to do the other tests - you don't even need to build thunk computing them; and the compiler cannot know (without profile-guided optimization) which is the code path which will be executed the most, while you should have a reasonable guess (in general you need profiling to verify that).

So what you want is something like the following (untested):

case x of
  10 -> stuff ()
  20 -> stuff ()
  _ -> case ((x > -10) && (x < 20),x /= 9,(x `mod` 2) == 0) of 
    (False,_,_) -> error "Not in range"
    (_,False,_) -> error "Must not be 9"
    (_,_,False) -> error "Must be even"
    _ -> error "Error Message"

Disclaimer: I did not verify what happens to this code and to the original one after all optimizations.


How's this? You're checking the conditions in order, and returning something on the first to fail, so make the conditions into a list and search through it.

fn x = case lookup False conds of
  Just ohno -> error ohno
  Nothing
    | x == 10 -> stuff
    | x == 20 -> stuff
    | otherwise -> error "Error Message"
 where
  conds = [
    (x > -10 && x < 20, "Not in range"),
    (x /= 9, "Must not be 9"),
    (even x, "Must be even")]
0

精彩评论

暂无评论...
验证码 换一张
取 消