过去两周我一直在学习Haksell,并决定在Hackerrank这样的地方尝试挑战。这需要学习IO。我已经在stackExchange上阅读了很多答案,而一般的要点是你没有打开IO ...你只是在IO函数中操作那些数据。那就是所有纯函数的重点是什么,如果我不允许从main发送数据给它们?下面是一些代码,它读取了多少个测试用例,然后每个测试用例读取N个有序对。
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,Int)]传递给validFunction。
答案 0 :(得分:7)
首先,如果您在x <- act
中使用do
,则基本上有一个值。除非您做了非常可疑的事情,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
。