麻烦在haskell中制作简单的功能

时间:2014-05-08 20:06:17

标签: haskell

我在尝试将以下C代码块转换为Haskell时遇到问题。

void echo(int num){
  if(num != 0) 
     print(num)
  else
     exit()
}

我刚刚开始学习Haskell,但我很困惑这样一个简单的函数如何如此困难。

1 个答案:

答案 0 :(得分:10)

在Haskell中看起来很困难的是,类型系统强制您将这些类型的功能与不改变机器状态的功能分开,例如打印到屏幕或退出程序。为了编写这样的函数,你必须使用IO monad:

import System.Exit   -- Need this for exitSuccess

--                v   The () is like void
echo :: Int -> IO ()
echo n =
    if n /= 0
        then print n
        else exitSuccess

正如您所看到的,Haskell中的这个定义与C风格的语言相比,本质上并不复杂。您只需导入包含用于退出的函数的模块,您必须编写函数以在IO monad中工作。您可以在程序中使用此功能

loop :: IO ()
loop = do
    putStr "Enter a number: "
    numStr <- getLine
    echo (read numStr)
    loop

main :: IO ()
main = loop

这段简短的代码段会不断提示用户输入一个号码,然后回复它,除非他们输入0


我在本回答的开头提到,类型系统不允许您将状态更改代码与非状态更改代码混合使用。它是如何做到的?在这种情况下,具有以IO a结尾的类型签名的任何函数(其中a可以是任何东西)在IO monad中执行,并且仅在该monad上下文中执行。所以你不能做像

这样的事情
doubler :: Int -> Int
double n = 2 * (echo n)

这不是类型检查! 2 *期望下一个参数为Int,而echo n的类型为IO ()。即使它具有IO Int类型,也与类型Int不同或兼容。如果你有了

doubler :: Int -> IO Int
doubler n = do
    echo n
    return (2 * n)

然后您可以将其用作

loop :: IO ()
loop = do
    putStr "Enter a number: "
    numStr <- getLine
    nDoubled <- doubler (read numStr)
    putStr "Your number doubled is "
    print nDoubled
    loop

显然,这将回显原始号码,如果它是0,则退出程序,然后打印Your number doubled is <n> <n>是新号码,然后重复此过程直到0进入了。