4

I am really new to Haskell and also really confused about how to implement for loops since I know we need to use recursion for them.

For example, I have a list [1,2,2,4,1] and want to write a function to change every 2 to a 3. How would I go about doing this? In Java, I know I would write the following

public void replace_two(List<Integer> ints) {
        int i = 0;
        for (int x: ints) {
            if (x == 2) {
                ints.set(i, 3);
            }
            i++;
        }
        System.out.println(ints);
    }

but I am not sure how I could reproduce something else like this with Haskell?

3
  • 6
    In Haskell, all data is immutable, you thus do not alter the value in a list, you create a new list with altered values. This is similar to how you do string processing in Java. Commented Sep 9, 2019 at 7:48
  • Functional programming can be radically different from imperative programming. A common mistake is trying to think how to solve a problem in an imperative programming language (Java, C, python, ...) and after that trying to translate it into a FP language. This will either make you stuck, or lead to ugly code. Instead, I would recommend you "unlearn" most of your programming habits, and learn FP and Haskell from scratch, following a tutorial like LYAH. Commented Sep 9, 2019 at 11:30
  • Take a look at section How to think about loops in Real World Haskell Chapter 4. Functional programming Commented Sep 12, 2019 at 14:46

5 Answers 5

12

There's not a single replacement for a for loop in Haskell. The replacement depends on exactly what you want to do. In this case, a map would be appropriate:

replace_two = map go
  where
    go 2 = 3
    go x = x

And it works like this:

Prelude> replace_two [1,2,2,4,1]
[1,3,3,4,1]
Prelude>
Sign up to request clarification or add additional context in comments.

Comments

4

Haskell uses a combination of different ways to 'sort of' loop over data, e.g. list.

The two important things helping this is:

  1. Ease of declaring a function and passing it around similar to what we do to a variable in oops languages
  2. Extensive pattern matching

So for example I declare a function in haskell to return 2 if input is 3 else return input.

return2 x = if x == 3 then 2 else x

Now we want to apply this function to every element of the list. So we will use pattern matching.

apply (x:xs) = return2 x : apply xs
apply [] = []

Here the pattern x:xs will break the list and take the first element in x while xs will have the remainder of the list. Inside the function you can see we have applied it recursively.

I have not checked the above code in IDE so it might have syntax errors, also there are other things you will want to validate (end of list, in above code the function would cause exception).

The above pattern is quite common, so there is another function in the core libraries that can do this, and is called map. So you could do:

map return2 [your list]

As I said, in haskell there are many ways to essentially loop over things, but at the base they break down to applying the function to individual items in the data structure. There are many haskell functions built on top of it like map, fold, etc.

I would suggest you use one of the several resources online to get more familiar with Haskell constructs. One that I liked and was easy to follow is Learn you a Haskell

Comments

2

Using map with an anonymous function:

λ> map (\x -> if x==2 then 3 else x) [1,2,2,4,1]
[1,3,3,4,1]

Comments

1

Another basic approach using patterns and recursion.

replace :: [Int] -> [Int]
replace [] = [] -- base case
replace (2:x)  = 3:replace(x) --if 2 then replace by 3
replace (y:x) = y:replace(x) -- do nothing

Comments

-1

Except map, maybe you can use forM from Control.Monad to mimic the for loop in other imperative languages:

import Control.Monad
arr = [1, 2, 2, 4, 1]
forM arr $ \i ->
    if i == 2 then return 3 else return i

However, you need to understand what is Monad.

1 Comment

Downvote for introducing a layer of monadic indirection (and return) for no good reason. If you really want the parameters to be backward, just use <&> from Data.Functor.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.