2017-04-05 32 views
1

過去兩週我一直在學習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。

+4

您無法將'IO a'變成'a'。你需要用'fmap validFunction'來獲得'IO [(Int,Int)] - > IO Bool',然後使用它。一旦你執行了IO,你永遠不會有一個沒有顯示IO正在執行的類型 - 按設計。 – chi

+0

是的,我明白從我讀過的所有答案中。我似乎無法找到的是任何明確的示例,顯示我需要的語法。這似乎都涉及停留在主內的代碼。我找不到任何代碼使用您建議的語法從do塊調用「純函數」。 –

+0

'rs'的類型是什麼?如果它是'IO [(Int,Int)]',那麼你需要'fmap validFunction rs',它的類型是'IO Bool'。 – Lee

回答

7

首先,如果您在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 

然而,IOFunctor一個實例,所以我們可以用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) 

後者是難讀,但。但你寫fooDodoTest如你想do

+0

很好的解釋。可悲的是,在所有關於我做的事情中,我確實返回了validFunction rs,但缺少()或$讓我了。我一直忘記它的正確聯想。 –

+3

@TonyChamberlain'return'是一個函數,而不是關鍵字。這是人們必須記住的關鍵(赫)。 – Zeta