3 ms·
True. OK, let's start with the OP's goal, not his code (which appears to have been consistently incorrect, conveniently and humorously contradicting his intende
by wyager 10y ago
True. OK, let's start with the OP's goal, not his code (which appears to have been consistently incorrect, conveniently and humorously contradicting his intended point).
> The goal is to skip the line after a line starting with the letter "a".
OK, so we want the following:
["x", "y", "a", "skip", "z"] -> ["x", "y", "a", "z"]
Here's a non-clever but still more elegant (and correct) way:
f (x:y:zs)
| ('a':_) <- x = x : f zs
| otherwise = x : f (y : zs)
f zs = zs
I guarantee you that there are multiple zippy one-liners that do the same thing, but I'll leave it at that for now. It's already a huge improvement, and does what it purports to!
- uryga 10y ago('a':_) <- x = x : f zs What's the `<- x`for? I know some Haskell and I've never seen that syntax. And `('a':_) = x : f zs` should be enough I think. Also I'm pretty sure each line is supposed to be a string, so it should be `("a":_) = x : f zs` :)
- dllthomas 10y agoThat's pattern-guard syntax. The bits between | and = ("the guard") are tried in turn, and the stuff to the right of the = is done for the first that succeeds. This can also introduce new bindings, although it doesn't here. To do this directly without guards, it'd be: f (x@('a':_):_:zs) = x : f zs f (x:ys) = x : f ys f [] = [] Not obviously better, not obviously worse.
- uryga 10y agoThanks, I get it now! I know how guards work, I've just never seen a construct like `('a':_) <- x` (and misunderstood the task a bit :). My understanding is, that's basically inline do-notation, is that correct?. On a sidenote. I've seen code like `f (x:ys) = x : f ys` many times, for example in definitions of map or filter. It always seemed to me like we're wasting a lot of breath typing that - deconstructing the list with pattern matching, then reassembling it again, slightly changed. I feel like there's a general pattern here that could be factored out, do you know of anything like that?
- dllthomas 10y ago> My understanding is, that's basically inline do-notation, is that correct?. Not really. They're superficially similar, but translate differently. Do-notation desugars `x <- y` to `y >>= \ x -> ...`, whereas the pattern guard is more like 'case y of x -> ...; _ -> ...'. Most importantly, there is not necessarily any monad involved for pattern guards - `5 <- 5` is legitimate. `5 <- 5` is nonsensical in do notation (without some awfully weird instance of `Num`). > On a sidenote. I've seen code like `f (x:ys) = x : f ys` many times, for example in definitions of map or filter. It always seemed to me like we're wasting a lot of breath typing that - deconstructing the list with pattern matching, then reassembling it again, slightly changed. I feel like there's a general pattern here that could be factored out, do you know of anything like that? The general pattern, for map and filter, is a fold. Prelude Test.QuickCheck> let map' f = foldr (\ x -> (f x:)) [] Prelude Test.QuickCheck> let filter' f = foldr (\ x -> if f x then (x:) else id) [] Prelude Test.QuickCheck> quickCheck $ \ (Blind f, xs) -> map f xs == map' f xs +++ OK, passed 100 tests. Prelude Test.QuickCheck> Prelude Test.QuickCheck> quickCheck $ \ (Blind f, xs) -> filter f xs == filter' f xs +++ OK, passed 100 tests.