Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simplify haskell function

Tags:

haskell

I'm really struggling with Haskell atm.

It took me almost 6 hours to write a function that does what I want. Unfortunately I'm not satisfied with the look of it.

Could someone please give me any hints how to rewrite it?

get_connected_area :: Eq generic_type => [[generic_type]] -> (Int, Int) -> [(Int,Int)] -> generic_type -> [(Int,Int)]
get_connected_area habitat point area nullValue
  | elem point area = area
  | not ((fst point) >= 0) = area
  | not ((snd point) >= 0) = area
  | not ((fst point) < (length habitat)) = area
  | not ((snd point) < (length (habitat!!0))) = area
  | (((habitat!!(fst point))!!(snd point))) == nullValue = area
  | otherwise = 
    let new_area = point : area
    in 
    get_connected_area habitat (fst point+1, snd point) (
        get_connected_area habitat (fst point-1, snd point) (
            get_connected_area habitat (fst point, snd point+1) (
                get_connected_area habitat (fst point, snd point-1) new_area nullValue
                ) nullValue
            ) nullValue
    ) nullValue

The function get's a [[generic_type]] (representing a landscape-map) and searches the fully connected area around a point that isn't equal to the given nullValue.

Eg.:

If the function gets called like this:

get_connected_area [[0,1,0],[1,1,1],[0,1,0],[1,0,0]] (1,1) [] 0

That literally means

0 1 0
1 1 1
0 1 0
1 0 0

Represents a map (like google maps). Start from the point (coordinates) (1,1) I want to get all coordinates of the elements that form a connected area with the given point.

The result therefore should be:

0 1 0
1 1 1
0 1 0
1 0 0

And the corresponting return value (list of coordinates of bold 1s):

[(2,1),(0,1),(1,2),(1,0),(1,1)]

like image 367
infotoni91 Avatar asked Sep 03 '17 16:09

infotoni91


People also ask

What is a function in Haskell?

Haskell - Functions. Functions play a major role in Haskell, as it is a functional programming language. Like other languages, Haskell does have its own functional definition and declaration. Function declaration consists of the function name and its argument list along with its output.

Does f x y = g (x/y) hold in Haskell?

It holds. f x y = g (x,y) , however the curried form is usually more convenient because it allows partial application . In Haskell, all functions are considered curried: That is, all functions in Haskell take just one argument. This is mostly hidden in notation, and so may not be apparent to a new Haskeller.

What is maplist in Haskell?

This higher-order function "mapList" can be used in a wide range of areas to simplify code. It is called map in Haskell's Prelude. Mathematical examples. In mathematics the counterpart to higher-order functions are functionals (mapping functions to scalars) and function operators (mapping functions to functions).

What is a lambda expression in Haskell?

We sometimes have to write a function that is going to be used only once, throughout the entire lifespan of an application. To deal with this kind of situations, Haskell developers use another anonymous block known as lambda expression or lambda function. A function without having a definition is called a lambda function.


1 Answers

One small change is that you can use pattern matching for the variable point. This means you can use (x, y) instead of point in the function declaration:

get_connected_area habitat (x, y) area nullValue = ...

Now everywhere you have fst point, just put x, and everywhere you have snd point, put y.

Another modification is to use more variables for subexpressions. This can help with the nested recursive calls. For example, make a variable for the inner-most nested call:

....
where foo = get_connected_area habitat (x, y-1) new_area nullValue

Now just put foo instead of the call. This technique can now be repeated for the "new" inner-most call. (Note that you should pick a more descriptive name than foo. Maybe down?)

Note that not (x >= y) is the same as x < y. Use this to simplify all of the conditions. Since these conditions test if a point is inside a bounding rectangle, most of this logic can be factored to a function isIn :: (Int, Int) -> (Int, Int) -> (Int, Int) -> Bool which will make get_connected_area more readable.

like image 130
Code-Apprentice Avatar answered Sep 19 '22 06:09

Code-Apprentice