Haskell:I/O和从函数返回

Ben*_*ver 6 io monads haskell types

请耐心等待,因为我对函数式编程和Haskell都很陌生.我试图在Haskell中编写一个函数,它接受一个I​​ntegers列表,打印所述列表的头部,然后返回列表的尾部.该函数需要是[Integer] - > [Integer]类型.为了给出一些上下文,我正在编写一个解释器,当在关联列表中查找其各自的命令时调用此函数(键是命令,值是函数).

这是我写的代码:

dot (x:xs) = do print x
      return xs
Run Code Online (Sandbox Code Playgroud)

编译器给出以下错误消息:

forth.hs:12:1:
Couldn't match expected type `[a]' against inferred type `IO [a]'
  Expected type: ([Char], [a] -> [a])
  Inferred type: ([Char], [a] -> IO [a])
In the expression: (".", dot)
Run Code Online (Sandbox Code Playgroud)

我怀疑点函数中的打印调用是导致推断类型为IO [a]的原因.有什么方法可以忽略返回类型的打印,因为我需要返回的是列表的尾部被传递到点.

提前致谢.

gaw*_*awi 8

在大多数功能语言中,这都可行.但是,Haskell是一种函数式语言.您不能在函数中执行IO,因此函数可以是

  1. [Int] -> [Int] 没有执行任何IO或
  2. [Int] -> IO [Int] 与IO

dot编译器推断的类型是,dot :: (Show t) => [t] -> IO [t]但您可以将其声明为[Int] -> IO [Int]:

dot :: [Int] -> IO [Int]

请参阅IO monad:http://book.realworldhaskell.org/read/io.html


我没有提到System.IO.Unsafe.unsafePerformIO应该非常小心地使用它并且对其后果有一个坚定的理解.

  • [`Debug.Trace`](http://www.haskell.org/ghc/docs/6.12.2/html/libraries/base-4.2.0.1/Debug-Trace.html)模块可用于打印东西同样. (3认同)

sth*_*sth 8

不,您的功能会导致副作用(也就是IO,在这种情况下在屏幕上打印),或者它不会.print是IO,因此返回一些内容IO,这是无法撤消的.

如果编译器可能被欺骗而忘记了,那将是一件坏事IO.例如,如果[Integer] -> [Integer]在程序中使用相同的参数多次调用函数([]例如),编译器可能只执行一次函数并在函数被"调用"的所有位置使用该函数的结果. .即使您在多个地方调用了该功能,您的"隐藏"打印也只会执行一次.

但类型系统可以保护您并确保所有使用的功能IO,即使只是间接使用,也有一个IO类型来反映这一点.如果你想要一个纯粹的功能,你不能print在其中使用.


Dan*_*att 6

您可能已经知道,Haskell是一种"纯粹的"函数式编程语言.出于这个原因,副作用(例如在屏幕上打印值)不是偶然的,因为它们是更主流的语言.这个事实为Haskell提供了许多不错的属性,但是当你所做的只是试图在屏幕上打印一个值时,你可以原谅你不关心它.

因为该语言没有引起副作用的直接设施,所以策略是函数可以产生一个或多个"IO动作"值.IO操作封装了一些副作用(打印到控制台,写入文件等)以及可能产生的值.你的dot功能就是产生这样的动作.您现在遇到的问题是您需要能够导致IO副作用的东西,以及展开值并可能将其传回程序.

如果不诉诸黑客,这意味着您需要将IO操作备份到该main功能.实事求是地讲,这意味着之间的所有内容main,并dot已在"IO单子"."IO Monad"中发生的事情可以保留在"IO Monad"中.

编辑

这是关于dot在有效的Haskell程序中使用函数我可以想象的最简单的例子:

module Main where

main :: IO ()
main =
    do
        let xs = [2,3,4]
        xr <- dot xs
        xrr <- dot xr
        return ()

dot (x:xs) =
    do
        print x
        return xs
Run Code Online (Sandbox Code Playgroud)