I tend to prefer where, but I think that guards & function declarations are more readable than giant if-thens and case constructs.
"where" can scope over multiple guards, and guards can access things declared in a "where" clause, both of which are important features:
f xs | len > 2 = y
| len == 1 = 0
| otherwise = -y
where
len = length xs
y = ...
compare to
f xs =
let len = length xs
y = ...
in if len > 2 then y
else if len == 1 then 0
else -y
The indenting hides the structure of the second function.
-- ryan