我有一个家庭作业问题问我:
你能写一个类型为IO Int的Haskell函数 - > Int(不使用unsafePerformIO)?如果是,请给出功能;如果没有,请解释原因。
我试过写这样一个函数:
test :: IO Int -> Int
test a = do
x <- a
return x
但这不起作用。我试图让它工作一段时间,我不能,所以我认为这个问题的答案是否定的。但是,我不明白为什么不可能。为什么它不起作用?
答案 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
玩得开心......
免责声明:这一切都非常讨厌;)