Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Haskell allow a let expression for multiple pattern matchings?

Let's say I have a function which does some computation, with several patterns; implemented in the form of pattern matching.

Most of these patterns do (along with other things different from one to another) a treatment on a parameter, for which I use an intermediary variable in a let expression. But I find it really redundant to have the same let on many patterns, and I wonder if there is a way to define a let for several patterns?

Here is an example of my duplicated let :

data MyType a = Something a | Another Int [a]

myFunc (Something x) = -- return something, this isn't the point here
myFunc (Another 0 xs) =
    let intermediary = some $ treatment xs
    in doSthg intermediary 1 
myFunc (Another 1 (x:xs)) =
    let intermediary = some $ treatment xs
    in doSthg1 intermediary 1 x
myFunc (Another 2 (x:x':xs)) =
    let intermediary = some $ treatment xs
    in doSthg2 intermediary 2 x x'

You can see that the parameter xs is always present when I use it for intermediary, and this could be factorised. It could easily be achieved by using a helper function but I was wondering if what I am asking is possible without one. Please try to keep it simple for a beginner, and I hope my example is clear enough.

like image 496
teh internets is made of catz Avatar asked Mar 14 '13 19:03

teh internets is made of catz


1 Answers

This particular problem can be worked around as follows:

myFunc2 (Something x) = returnSomething x
myFunc2 (Another n ys) = 
    let xs = drop n ys
        x = head ys 
        x' = head (tail ys)
        intermediate = some $ treatment xs 
    in case n of
        0 -> doSomething intermediate n
        1 -> doSomething1 intermediate n x
        2 -> doSomething2 intermediate n x x'

Thanks to lazy evaluation x and x' will be only evaluated if their value is needed.

However - and this is a big however! - your code will give a runtime error when you try to call myFunc2 (Another 2 []) (and if doSomething2 actually uses x!) because to find out what x is, we need to evaluate head ys - and that'll crash for an empty list. The code you gave as an example also won't work (another runtime error) for Another 2 [] since there's no matching pattern, but there it's easier to supply a fall-back case.

This might not be a problem if you control the input and always make sure that the list in Another is long enough, but it's important to be aware of this issue!

like image 162
yatima2975 Avatar answered Oct 09 '22 08:10

yatima2975