【问题标题】:What is the equivalent statement of a while loop in Haskell?Haskell中while循环的等效语句是什么?
【发布时间】:2021-05-25 00:00:06
【问题描述】:

作为 Haskell 的新手,我想知道如何 1)计算某些东西直到满足某个标准,然后 2)返回计算值。

在我知道的语言中,您会为此使用 while 循环。在 Haskell 中你是怎么做的?

【问题讨论】:

  • Haskell 使用递归代替循环。
  • @Jubobs:我认为您不能说对于一般情况,因为映射、折叠和过滤也用于代替循环。当然,除了更多其他功能甚至功能库。它总是取决于;我想说的是,在第一级工具阵容中,它是映射、过滤、折叠和递归。
  • @phresnel Haskell 的mapfilter 和折叠都是作为递归函数实现的……这些函数只是在递归之上添加了一层抽象,但你总是在底部找到递归这一切。
  • @Jubobs:是的,我不否认这一点。但是例如C++ 中的 lambda 被实现为具有函数调用运算符的类;但是您不会建议在 lambda(作为工具)更合适的情况下使用带有函数调用运算符的 。你会说 Haskell 的 map et al 不如“原始”递归那么惯用和/或可取吗?
  • @phresnel 不。您应该在适当的时候使用mapfilterfoldr 等,但我想说的是,归根结底,递归规则所有这些。

标签: haskell while-loop


【解决方案1】:

你应该使用递归

func :: <function type>
func <arguments> = 
    if condition 
        then <recursive call>
        else computedValue

您将来还会发现其他实用程序,例如until,可以帮助您解决此问题。最后,它实际上取决于循环和条件的语义。例如,如果条件只是“直到我们到达列表末尾”,您可以简单地使用 mapfold-family 函数之一。

【讨论】:

  • 当条件满足时,我想在 else 语句中返回一个列表。例如,`fun [] = [] fun (x:xs) = if x == 0 then x:fun xs else ...' 例如我给出了列表 [1,2,0,3,4] 所以它应该返回 [1,2]。
  • @Myke 如果您以某种语言给出一些 while 循环作为示例,我可能会向您展示 Haskell 中的等价物。
  • 例如,`fun [] = [] fun (x:xs) = if x == 0 then x:fun xs else ...' 比如我给了列表 [1,2 ,0,3,4] 所以它应该返回 [1,2]
  • @Myke Try fun = takeWhile (/= 0).
  • 不..我并没有完全实现上面的例子..但它是类似的类比
【解决方案2】:

Haskell 没有基于可变状态的 while 循环的内在等效项。

相反,您通常

  • 在一系列值上使用 map 系列函数来生成新的值范围
  • 在一系列值上使用 filter 系列函数来生成该范围的新子集,同时满足某些条件
  • 使用fold 系列函数来聚合该范围内的内容
  • 使用递归来做任何你想做的事(当然除了改变输入)。

.

当然,Haskell 和库提供了使您的生活更轻松的函数,但是 while 循环在命令式语言中可以被视为惯用/“一流”,而在 Haskell(以及其他函数式)中,什么是惯用/“一流”编程语言)是递归、映射、过滤和折叠。

【讨论】:

  • 并没有真正回答这个问题。您不会使用 map、filter 或 fold 来完成问题所要求的操作。
  • @JacquesB:通过“如何计算一些东西”我不能排除应该使用地图、过滤器或折叠。你的算命很棒。
【解决方案3】:

答案是递归。举一个迂腐的例子:

在 Python 中:

def fib(n):
    a = 0
    b = 1
    while n > 0:
        a, b = b, a + b
        n -= 1
    return b

在 Haskell 中:

fib 0 = 1
fib 1 = 1
fib n = fib (n - 1) + fib (n - 2)

或者等效地没有模式匹配

fib n = if n == 0 || n == 1 then 1 else fib (n - 1) + fib (n - 2)

或者更高效

-- the local variable fibs is an infinite list of all Fibonacci numbers
fib n = fibs !! n where fibs = 1 : 1 : zipWith (+) fibs (tail fibs)

如果你想做一些事情,比如从STDIN 读取文本,直到你得到一个读为q 的行,那么最简单的方法就是

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

或者在 Python 中

def prompt():
    l = input()
    while l != "q":
        # Assuming Python 3
        print("You entered: " + l)
        l = input()

【讨论】:

  • 可能值得一提的是为什么 fib 的第一个和第二个 Haskell 版本是个坏主意。
  • 一些有用的循环控制结构也在Control.Monad.Loops中定义。
【解决方案4】:

面临同样的问题,我需要将 C 转换为 Haskell。关键概念是条件和内置的 if-then-else 语句。

假设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;
}

将其转换为 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

【讨论】:

    猜你喜欢
    • 2022-01-12
    • 2018-08-06
    • 2020-08-15
    • 2014-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多