简体   繁体   English

在haskell中使简单功能麻烦

[英]Trouble making simple function in haskell

I am having trouble trying to convert the following block of C code into Haskell. 我在尝试将以下C代码块转换为Haskell时遇到麻烦。

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

I just started learning Haskell, but I am pretty confused as to how such a simple function could be so difficult. 我刚刚开始学习Haskell,但是对于如此简单的功能是如此困难,我感到非常困惑。

What makes it seem difficult in Haskell is that the type system forces you to separate these kinds of functions from those that do not alter the state of the machine, such as printing to the screen or exiting the program. 在Haskell中似乎很难做到的是,类型系统迫使您将这些类型的功能与那些不会改变机器状态的功能区分开,例如打印到屏幕或退出程序。 In order to write a function like this you have to use the IO monad: 为了编写这样的函数,您必须使用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

As you can see, there's nothing inherently more complex about this definition in Haskell than in the C-style languages. 如您所见,Haskell中的此定义在本质上没有C语言风格中的复杂。 You just have to import the module that contains the function used to exit, and you have to write your function to work in the IO monad. 您只需要导入包含用于退出的功能的模块,就必须编写要在IO monad中工作的功能。 You can use this function in a program as 您可以在程序中使用以下功能:

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

main :: IO ()
main = loop

This short snippet of code will continuously prompt the user for a number, then echo it back unless they enter 0 . 这段简短的代码将不断提示用户输入数字,然后回显它,除非他们输入0


I mentioned at the beginning of this answer that the type system doesn't let you mix state altering code with non-state altering code. 我在这个答案的开头提到类型系统不允许您将状态更改代码与非状态更改代码混合使用。 How does it do this? 它是如何做到的? In this case, any function with a type signature that ends with IO a (where a can be anything) executes in the IO monad, and only in that monad context. 在这种情况下,任何类型签名以IO a结尾的函数(其中a可以是任何东西)都在IO monad中执行,并且仅在该monad上下文中执行。 So you can't do something like 所以你不能做这样的事情

doubler :: Int -> Int
double n = 2 * (echo n)

This won't type check! 这不会输入检查! 2 * expects the next argument to be an Int , whereas echo n has the type IO () . 2 *期望下一个参数为Int ,而echo n的类型为IO () Even if it had the type IO Int , this is not the same as or compatible with the type Int . 即使有型IO Int ,这是不一样的或兼容的类型Int If instead you had 相反,如果你有

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

You could then use it as 然后,您可以将其用作

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

Obviously, this will echo the original number, or exit the program if it's 0, then print Your number doubled is <n> where <n> is the new number, and then repeat this process until a 0 is entered. 显然,这将回显原始数字,或者如果它为0,则退出程序,然后打印Your number doubled is <n> ,其中<n>是新数字,然后重复此过程直到输入0。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM