具有类型IO Int的Haskell函数 - > Int,不使用unsafePerformIO

时间:2014-11-29 08:05:03

标签: haskell io

我有一个家庭作业问题问我:

你能写一个类型为IO Int的Haskell函数 - > Int(不使用unsafePerformIO)?如果是,请给出功能;如果没有,请解释原因。

我试过写这样一个函数:

test :: IO Int -> Int
test a = do 
    x <- a
    return x

但这不起作用。我试图让它工作一段时间,我不能,所以我认为这个问题的答案是否定的。但是,我不明白为什么不可能。为什么它不起作用?

2 个答案:

答案 0 :(得分:4)

类型IO Int -> Int的唯一函数是无趣的,因为它们必须忽略它们的论点。也就是说,它们必须等同于

n :: Int
n = ...

f :: IO Int -> Int
f _ = n

(从技术上讲,还有f x = x `seq` n,正如@Keshav指出的那样。)

这是因为没有办法逃脱IO monad(与大多数其他monad不同)。这是设计的。考虑

getInt :: IO Int
getInt = fmap read getLine

是从stdin读取整数的函数。如果我们可以写

n :: Int
n = f getInt

这将是一个整数值,它可以依赖&#34;关于IO动作getInt ......但必须是纯粹的,即必须完全没有IO。如果我们必须完全没有IO,我们如何使用IO操作?事实证明,我们不能以任何方式使用它。

有意义地进行此类操作的唯一方法是允许程序员打破纯度&#34;合同,这是Haskell背后的主要内容。 GHC为程序员提供了一些不安全的&#34;如果程序员足够大胆地声明&#34;相信我,我知道我在做什么&#34;。其中一个是&#34; unsafePerformIO&#34;。另一个是访问realWorld#模块中的GHC.*低级别内容(如@Michael所示)。甚至FFI也可以导入一个声称它是纯粹的C函数,基本上使用户能够编写自己的unsafePerformIO

答案 1 :(得分:1)

嗯,有两种方法......

如果您对常量函数感到满意,请使用:

test :: IO Int -> Int
test a = 42

否则,您必须执行与unsafePerformIO相同的事情(或更具体地unsafeDupablePerformIO)。

{-# LANGUAGE MagicHash #-}
{-# LANGUAGE UnboxedTuples #-}

import GHC.Base (IO(..), realWorld#)

unIO (IO m) = case m realWorld# of (# _, r #) -> r

test :: IO Int -> Int
test a = (unIO a) + 1

玩得开心......

免责声明:这一切都非常讨厌;)