我在尝试将以下C代码块转换为Haskell时遇到问题。
void echo(int num){
if(num != 0)
print(num)
else
exit()
}
我刚刚开始学习Haskell,但我很困惑这样一个简单的函数如何如此困难。
答案 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进入了。