[Haskell-cafe] Guards (Was: Some random newbie questions)
Lemming
schlepptop at henning-thielemann.de
Sat Jan 8 12:46:04 EST 2005
Jon Cast wrote:
> Absolutely. In Haskell's syntax, if-then-else-if interacts badly with
> do notation, and Haskell lacks a direct analogy to Lisp's cond.
>
> case () of
> () | p1 -> e1
> | p2 -> e2
> ...
No problem:
select :: a -> [(Bool, a)] -> a
select def = maybe def snd . List.find fst
Use it this way:
select defaultE
[(p1, e1),
(p2, e2)]
Would be a nice Prelude function.
> parseCmd ln
> | Left err <- parse cmd "Commands" ln
> = BadCmd $ unwords $ lines $ show err
> | Right x <- parse cmd "Commands" ln
> = x
>
> with the Haskell-98 alternative
>
> parseCmd ln = case parse cmd "Commands" ln of
> Left err -> BadCmd $ unwords $ lines $ show err
> Right x -> x
Really, the second alternative is cleaner in my opinion.
> Furthermore, guards are an extension of pattern matching, which means
> you can write code like this:
>
> xn !! n | n < 0 = error "Prelude.(!!): Negative index"
> [] !! n = error "Prelude.(!!): Index overflow"
> (x:xn) !! n | n == 0 = x
> (x:xn) !! n = xn !! (n - 1)
>
> Exactly one equation for each edge in the control-flow graph, which is
> nice and not easily done (I'm not sure it's even possible) without
> guards.
At least one guard can nicely be avoided:
(x:xn) !! n = if n == 0 then x else xn !! (n - 1)
But I see that guards can be used to let pattern matching fail.
> Pattern guards are also nice for implementing â€˜viewsâ€™:
>
> -- | Convert an 'XMLData' into an equivalent application of
> -- 'Balanced', if possible. In any case, return an equivalent data
> -- structure.
> balance (Balanced es) = Balanced es
> balance (LeftLeaning (LeftBalanced e:es))
> | Balanced es' <- balance (LeftLeaning es)
> = Balanced (e:es')
I don't know what this means exactly, but I think I can transform it
formally to:
balance e'@(LeftLeaning (LeftBalanced e:es)) =
case balance (LeftLeaning es) of
Balanced es' -> Balanced (e:es')
_ -> e'
This way it is more clear for me, that 'balance' can return something
different from 'Balanced' and that the data is returned unchanged in
this case.
> balance (LeftLeaning []) = Balanced []
> balance (RightLeaning [("", "", es)]) = Balanced es
> balance (RightLeaning []) = Balanced []
> balance e = e
> Well, I could never do without them.
Sometimes I see people abusing guards, e.g. they write a 'length x == 1'
guard, where the pattern '[x0]' would be clearly the better choice. So
I'm always thinking twice before using a guard.
More information about the Haskell-Cafe
mailing list