展开从IO(a)
过去两周我一直在学习Haksell,并决定在Hackerrank等地尝试挑战。这需要学习IO。我已经阅读了stackExchange上的很多答案,一般的要点是你不打开IO ......你只是在IO函数内部操作这些数据。如果我不允许将数据从主数据发送给他们,那么这就是所有纯函数的意义所在?下面是一些读取多少个测试用例的代码,然后为每个测试用例读取N个有序对。展开从IO(a)
main = do
test <- getLine
replicateM (read test) doTest
doTest = do
query<-getLine
rs<-replicateM (read query) readPair
return rs -- just here to make the file compile
readPair :: IO (Int, Int)
readPair = do
input <- getLine
let a = words input in return (read (a!!0) :: Int, read (a!!1) ::Int)
此时我在rs内部有一个IO [(Int,Int)]。我想发送该数据到这个功能:
validFunction :: [(Int,Int)]->Bool
validFuntion [] = True
validFunction (x:[]) = True
validFunction (x:xs) = (not $ elem (snd x) (fmap snd xs)) && validFunction xs
但我似乎无法弄清楚如何做到这一点。对于如何用我从用户读取的数据调用这个函数的帮助或建议将不胜感激。或者如果我从一个错误的角度去谈论它,并且指出我应该做的事情也会起作用。
编辑:从阅读这里的很多其他问题,我已经得到了一般的想法,一旦你在IO你卡在那里。但我似乎无法找到的是使用IO数据调用纯函数并获取IO数据的语法。我已经尝试了一些如下:
fmap validFunction [rs] :: IO Bool -- tried it with just rs without [] as well
mapM validFunction [rs] :: IO Bool
validFunction rs :: IO Bool
我能得到这个工作:
putStrLn . f . validFunction $ rs
虽然我还没有,为什么这可以让你通过IO [清楚(智力,Int)]到validFunction。
首先,如果您在do
中使用x <- act
,那么您基本上有一个值。除非你做了非常可疑,x
不是IO something
,但something
:所以这是完全正常使用
foo :: Int -> Char
foo = …
bar :: IO Int
bar = …
fooDo :: IO Char
fooDo = do
number <- bar
return (foo number) -- apply foo directly on number
然而,IO
是Functor
一个实例,所以我们可以用fmap
到电梯foo
:
liftedFoo :: IO Int -> IO Char
liftedFoo = fmap foo
因此,我们可以这样写fooDo
这样的:
fooDo = fmap foo readLn
虽然它的名字现在是误导性的,它仍然和以前一样。但是让我们把这个命名巫术放在一边,你将如何解决这个问题?那么,你的doTest
具有正确类型:
doTest :: IO [(Int, Int)]
doTest = do
query <- getLine
rs <- replicateM (read query) readPair
return rs
所以所有缺少的是调用validFunction
。我们可以这样做在fooDo
:
doTest :: IO Bool
doTest = do
query <- getLine
rs <- replicateM (read query) readPair
return (validFunction rs)
-- ^^^^^^^^^^^^^^^^^^
-- no IO inside here
-- ^^^^^^
-- back
-- to IO
,或者我们可以fmap
对另一IO
值,如replicateM (read query) readPair
:
doTest :: IO Bool
doTest = do
query <- getLine
fmap validFunction (replicateM (read query) readPair)
后者是难读,但。但你写fooDo
doTest
如你想do
。
很好的解释。可悲的是,在所有关于我做的事情中,我确实返回了validFunction rs,但缺少()或$让我了。我一直忘记它的正确联想。 –
@TonyChamberlain'return'是一个函数,而不是关键字。这是人们必须记住的关键(赫)。 – Zeta
您无法将'IO a'变成'a'。你需要用'fmap validFunction'来获得'IO [(Int,Int)] - > IO Bool',然后使用它。一旦你执行了IO,你永远不会有一个没有显示IO正在执行的类型 - 按设计。 – chi
是的,我明白从我读过的所有答案中。我似乎无法找到的是任何明确的示例,显示我需要的语法。这似乎都涉及停留在主内的代码。我找不到任何代码使用您建议的语法从do块调用“纯函数”。 –
'rs'的类型是什么?如果它是'IO [(Int,Int)]',那么你需要'fmap validFunction rs',它的类型是'IO Bool'。 – Lee