繁体   English   中英

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

[英]Haskell function with type IO Int -> Int, without using unsafePerformIO

我有一个作业问题问我:

您可以编写IO Int-> Int类型的Haskell函数(不使用unsafePerformIO)吗? 如果是,请给出功能; 如果没有,请说明原因。

我试图编写这样的函数:

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

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

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

n :: Int
n = ...

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

(从技术上讲,还有fx = x `seq` n Keshav指出的fx = x `seq` n )。

这是因为无法逃避IO monad(与大多数其他monad不同)。 这是设计使然。 考虑

getInt :: IO Int
getInt = fmap read getLine

这是一个从stdin读取整数的函数。 如果我们能写

n :: Int
n = f getInt

这将是一个整数值,可以“取决于” IO操作getInt ...,但必须是纯值,即必须完全不做任何IO。 如果我们根本不需要执行任何IO操作,该如何使用IO操作? 事实证明,我们不能以任何方式使用它。

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

好吧,有两种方法...

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

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

玩得开心...

免责声明:这真的很hacky;)

暂无
暂无

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

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