Being very new to Haskell, I'm wondering how to 1) compute something until a certain criterion is satisfied, and then 2) return the computed value.
In the languages I know, you would use a while loop for that. How do you do it in Haskell?
Being very new to Haskell, I'm wondering how to 1) compute something until a certain criterion is satisfied, and then 2) return the computed value.
In the languages I know, you would use a while loop for that. How do you do it in Haskell?
You should use recursion:
func :: <function type>
func <arguments> =
if condition
then <recursive call>
else computedValue
There are also other utilities you'll discover in the future, such as until
, that will help you with this. In the end it really depends on the semantic of the loop and condition. For example if the condition is simply "until we reach the end of a list" you can simply use map
or one of the fold
-family functions.
The answer is recursion. To give a pedantic example:
In Python:
def fib(n):
a = 0
b = 1
while n > 0:
a, b = b, a + b
n -= 1
return b
In Haskell:
fib 0 = 1
fib 1 = 1
fib n = fib (n - 1) + fib (n - 2)
Or equivalently without pattern matching
fib n = if n == 0 || n == 1 then 1 else fib (n - 1) + fib (n - 2)
Or more efficiently
-- the local variable fibs is an infinite list of all Fibonacci numbers
fib n = fibs !! n where fibs = 1 : 1 : zipWith (+) fibs (tail fibs)
If you want to do something like read text from STDIN
until you get a line that reads q
, then the easiest way is something like
import Control.Monad (unless)
prompt :: IO ()
prompt = do
-- get input from user
l <- getLine
-- unless will execute its block if the condition is False
unless (l == "q") $ do
-- echo back to the user
putStrLn $ "You entered: " ++ l
prompt -- recursive step here
Or in Python
def prompt():
l = input()
while l != "q":
# Assuming Python 3
print("You entered: " + l)
l = input()
Haskell does not have an intrinsic equivalent of while
loops based on mutable state.
Instead, you typically
map
family of functions over a range of values to produce a new range of valuesfilter
family of functions over a range of values to produce a new subset of that range, with certain conditions fulfilledfold
family of functions to aggregate something over that range.
Of course, Haskell and libraries provide functions to make your life easier, but while while
loops can be considered idiomatic/"first class" in imperative languages, what is idiomatic/"first class" in Haskell (and other functional programming languages) is recursion, mapping, filtering and folding.
Facing the same problem that I need to convert C to Haskell. The key concepts are the conditions and the built-in if-then-else statements.
Say there's a program in C
int auto_drive (int speed) {
int speed_limit = 90;
while (speed > 0 & speed != speed_limit) {
if (speed > speed_limit) {
speed = speed - 1;
} else {
speed = speed + 1;
}
}
return speed;
}
Convert it to Haskell:
auto_drive :: Int -> Int
auto_drive speed = mywhile (90,speed)
mywhile x =
if condition x then mywhile (next_version_of x) -- if condition met, pass x to the function next_verion_of, next, recursion back to mywhile function
else final_version_of x -- otherwise, it would have the final speed
condition (speed_limit,speed) = speed > 0 && speed /= speed_limit
next_version_of (speed_limit,speed) =
if speed > speed_limit then (speed_limit,speed-1) else (speed_limit,speed+1) -- converge the speed to the speed limit
final_version_of (speed_limit,speed) = speed