Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 有没有办法从IO单子中打开类型?_Haskell_Io_Monads_Io Monad - Fatal编程技术网

Haskell 有没有办法从IO单子中打开类型?

Haskell 有没有办法从IO单子中打开类型?,haskell,io,monads,io-monad,Haskell,Io,Monads,Io Monad,我有一个非常简单的函数 import qualified Data.ByteString.Lazy as B getJson :: IO B.ByteString getJson = B.readFile jsonFile readJFile :: IO (Maybe Response) readJFile = parsing >>= (\d -> case d of Left err -> return

我有一个非常简单的函数

import qualified Data.ByteString.Lazy as B

getJson :: IO B.ByteString
getJson = B.readFile jsonFile

readJFile :: IO (Maybe Response)
readJFile =  parsing >>= (\d ->
             case d of
                 Left err -> return Nothing
                 Right ps -> return (Just ps))
    where parsing = fmap eitherDecode getJson :: IO (Either String Response)
其中
jsonFile
是指向硬盘上文件的路径(请原谅,没有do符号,但我发现这更便于使用)

我的问题是,;有没有一种方法可以让我放弃
IO
部分,这样我就可以单独使用bytestring了

我知道你可以在某些单子上进行模式匹配,比如
或者
或者
或者
来获取它们的值,但是你能用
IO
做类似的事情吗

或者用不同的声音:有没有办法让我在没有IO的情况下返回
readJFile
return
Maybe Response

你永远不需要在任何函数中“拖动单子”,除非它们都需要实际执行IO。只需使用
fmap
(或
liftM
/
liftM2
/…)将整个链条提升到monad中即可

比如说,

f1 :: B.ByteString -> K
f2 :: K -> I
f3 :: K -> J
f4 :: I -> J -> M
你的整个事情应该是这样的

m :: M
m = let k = "f1 getJson"
    in f4 (f2 k) (f3 k)
您可以简单地执行以下操作:

m = fmap (\b -> let k = f1 b
                in f4 (f2 k) (f3 k) )
    getJson
顺便说一句,使用
do
符号可能会更好:

m = do
  b <- getJson
  return $ let k = f1 b
           in f4 (f2 k) (f3 k)

总的来说,是的,有一种方法。伴随着很多的“但是”,但是有。您要求的是所谓的不安全IO操作。它用于在调用外部库时编写包装器。通常,在常规Haskell代码中不需要使用它

基本上,您可以调用
unsafePerformIO::IO a->a
,这正是您想要的,它去掉
IO
部分,并返回类型为
a
的包装值。但是,如果您查看文档,您应该向系统保证一些要求,这些要求最终都是相同的:即使您通过IO执行操作,答案应该是功能的结果,正如不在
IO
中运行的任何其他haskell函数所预期的那样:它应该始终具有相同的结果,并且没有副作用,仅基于输入值


这里,给定您的代码,情况显然不是这样,因为您是从文件中读取的。您只需在IO monad中继续工作,方法是从另一个结果类型为
IO something
的函数中调用您的
readJFile
。然后,您将能够读取
IO
包装中的值(您自己在
IO
中),处理它,然后在返回时将结果重新包装到另一个
IO
中。

要扩展我的评论,以下是您可以做到的方法:

getJson :: IO B.ByteString
getJson = B.readFile jsonFile -- as before

readJFile :: B.ByteString -> Maybe Response -- look, no IO
readJFile b = case eitherDecode b of
                Left err -> Nothing
                Right ps -> Just ps
最后,您再次将所有内容合并到一个IO操作中:

getAndProcess :: IO (Maybe Response)
getAndProcess = do
  b <- getJson
  return (readJFile b)
getAndProcess::IO(可能是响应)
getAndProcess=do

bNo,没有安全的方法从IO monad中获取值。相反,您应该通过使用fmap或bind(>>=)应用函数来完成IO monad内部的工作。另外,当你希望你的结果是正确的时,你应该使用decode而不是eitherDecode

getJson :: IO B.ByteString
getJson = B.readFile jsonFile

parseResponse :: B.ByteString -> Maybe Response
parseResponse = decode

readJFile :: IO (Maybe Response)
readJFile = fmap parseResponse getJSON
如果您更清楚,也可以使用do符号:

readJFile :: IO (Maybe Response)
readJFile = do
    bytestring <- getJson
    return $ decode bytestring
readJFile::IO(可能是响应)
readJFile=do

通过测试可能的重复:我不是在谈论内置的东西,我只是在寻找一种方法来实现它,也许我可以构建自己;按照我的代码现在的样子,我必须通过5个函数拖动IO单子,公平地说,它会把它弄得乱七八糟,特别是考虑到我只在这一个函数中执行IO操作,其他任何地方都不需要通过任何函数“拖动单子”,除非它们都需要实际执行IO。只需使用
fmap
(或
liftM
/
liftM2
/…)将整个链提升到monad中即可。如果其他函数不执行IO,则它们不应处于IO中。使它们依赖于bytestring(即,类型为
B.bytestring->…
),然后使用单个IO操作将读取与处理相结合。否
readJFile
不执行IO,因此它必须具有IO类型。但是你可以把它抽象到bytestring上,就像我上面说的。它很干净,很简单,我喜欢它!不幸的是,它根本不起作用all@ElectricCoffee您发布的错误似乎与我的代码没有什么关系。它提到了一行
Left err->return Nothing
,它没有出现在我的代码中,然后是另一行
Right ps->return Just ps
,它也没有出现在我的代码中。千万不要向初学者推荐
unsafePerformIO
。即使只是提到这一点,在某些情况下也似乎是一个合理的选择,但事实并非如此。初学者永远不需要使用或了解
unsafePerformIO
。我之所以提到这一点,是因为对我和其他人来说,当我们了解Haskell时,了解了《不安全的执行》实际上让学习变得更加困难,因为它给人的印象是,你应该在某个时候“突破”IO单子,而你不是。你真的读过我的答案了吗,easy downvote先生?我没有推荐,我只是陈述了一个事实。我的答案不是推广它,也不是错的。如果你不喜欢,就不要放弃它。在某些情况下,当您必须与外部库交互(可能为它们编写包装器)时,需要进行不安全的操作。好的,这不是初学者的东西,但是我应该和不应该告诉人们什么,这不是由你决定的,只要它是正确的。我还想说的是,SO是一个答案库,它容纳了任何正在搜索信息的人。尽管他是一个初学者,不需要unsafePerformIO,但提到它作为参考可能会对将来@kqr实际需要它的人有所帮助。
readJFile :: IO (Maybe Response)
readJFile = do
    bytestring <- getJson
    return $ decode bytestring