【问题标题】:While loop in Haskell with a conditionHaskell中的while循环有条件
【发布时间】:2013-07-18 09:29:39
【问题描述】:

我在这里遇到了一点 Haskell 情况。我正在尝试用 monads 编写两个函数。 只要函数的输入/输出条件为真,第一个就应该遍历函数。第二个应该使用第一个将数字作为输入并将其写入输出,直到您输入一个空格。

我被困住了,有什么帮助吗?

module Test where

while :: (a -> Bool) -> (a -> IO a) -> a -> IO a
while praed funktion x = do
                         f <- praed (funktion x)
                         if f == True then do
                                             y <- funktion x
                                             while praed funktion y
                         else return x



power2 :: IO ()
power2 = do putStr (Please enter a number.")
            i <- getChar
            while praed funktion
            where praed x = if x /= ' ' then False else True
                  funktion = i

【问题讨论】:

  • 那么您的问题是关于哪一个?你在哪里卡住了,什么不起作用?
  • 这两个函数甚至都没有编译,而且我很确定他们不会做我想让他们做的事情。我只是不知道如何在工作版本中编写它。我基本上是想让一个while循环处理一个条件。例如,while odd (square 3) 应该测试方格 3 是否为奇数,然后使用方格 3 = 9 的结果并执行while odd (square 9) 等等。从技术上讲,它不需要 x,它应该只适用于 while condition function

标签: loops haskell while-loop


【解决方案1】:
import Control.Monad

while :: (a -> Bool) -> (a -> IO a) -> a -> IO a
while praed funktion x
    | praed x   = do
        y <- funktion x
        while praed funktion y
    | otherwise = return x


power2 :: IO ()
power2 = do
    putStr "Please enter a number."
    i <- getChar
    let praed x = x /= ' '
    let f x = do
        putChar x
        getChar
    while praed f '?'
    return ()

一些注意事项:

  • 使用if x then True else False 是多余的,它相当于只是x
  • 同样if x == True ... 是多余的,等效于if x ...
  • 您需要区分IO 操作及其结果。例如,如果你这样做

    do
        i <- getChar
        ...
    

    那么在...i代表动作的结果,一个字符,所以i :: Char。但是getChar :: IO Char 是动作本身。您可以将其视为在执行时返回 Char 的配方。您可以将配方传递给函数等,并且仅在某处执行时才会执行。

  • 您的while 两次调用funktion,这可能不是您想要的 - 它会读取一个字符两次,检查第一个并返回第二个。请记住,您的funktion 是一个动作,因此每次您“调用”该动作(例如在do 符号中使用&lt;- funktion ...)时,该动作都会再次运行。所以它应该是这样的

    do
        y <- funktion x
        f <- praed y
        -- ...
    

    (我的代码有些不同,它会检查传递给它的参数。)

【讨论】:

  • 太棒了,谢谢。我理解你是如何做power2的,很有意义。我仍然不确定这段时间到底发生了什么。 praed 到底在什么时候检查条件是否为真?
  • @Chris 它在执行任何其他操作之前检查条件是否适用于其类型为 a 的参数,就像函数式语言中的 while 语句所做的那样。这是使用guards 完成的,这通常比if/then/else 更可取。 | praed x = do ... 行表示如果条件praed x 为真,则继续...。下一行| otherwise = ... 涵盖了所有其余情况(因为otherwise 只是True 的同义词,所以otherwise 是一个始终满足的条件)。
  • if x then True else False 不完全等同于x,但它等同于(x :: Bool)
【解决方案2】:

对于纯版本:

{-# LANGUAGE BangPatterns #-}

while :: (a -> Bool) -> (a -> a) -> a -> a
while p f = go where go !x = if p x then go (f x) else x

test1 :: Int
test1 = while (< 1000) (* 2) 2
-- test1 => 1024

对于单子:

import Control.Monad

whileM :: (Monad m, MonadPlus f) => (a -> m Bool) -> m a -> m (f a)
whileM p f = go where
  go = do
    x <- f
    r <- p x
    if r then (return x `mplus`) `liftM` go else return mzero

test2 :: IO [String]
test2 = whileM (return . (/= "quit")) getLine
-- *Main> test2
-- quit
-- []
-- *Main> test2
-- 1
-- 2
-- 3
-- quit
-- ["1","2","3"]

power2 :: IO (Maybe Char)
power2 = whileM (return . (/= 'q')) getChar
-- *Main> power2
-- q
-- Nothing
-- *Main> power2
-- 1
-- 2
-- 3
-- q
-- Just '\n'

另见:

http://hackage.haskell.org/package/monad-loopshttp://hackage.haskell.org/package/loop-whilehttp://hackage.haskell.org/package/control-monad-loop

http://www.haskellforall.com/2012/01/haskell-for-c-programmers-for-loops.html

【讨论】:

  • 另一个纯版本)while p = until (not . p)
猜你喜欢
  • 2016-06-08
  • 2012-10-20
  • 2015-02-27
  • 2012-11-05
  • 2014-04-30
  • 1970-01-01
  • 2022-11-12
  • 1970-01-01
  • 2023-03-05
相关资源
最近更新 更多