在檔案中,我正在保存檔案路徑。我想從檔案中讀取檔案路徑,然后將其轉換為變數,因此每次運行函式時,它都會從檔案中獲取當前檔案路徑,然后我可以在另一個函式中使用此字串。我知道變數是不可變的,但有什么辦法可以做到嗎?
如您所見,我正在嘗試從檔案中讀取檔案路徑,然后檢查它是否正確:
checksForCdCommand dir = checkIfPathExists constructedPath $ concat' $ paths sample2 where
constructedPath = do
let file = "abc.txt"
contents <- readFile file
return (if contents /= "/" then contents "/" dir else contents dir)
這里如果內容是“/”,這意味著它是我的根目錄,所以這就是為什么我有這個 if else 子句。但是由于以下原因,代碼無法通過這種方式編譯:
* Couldn't match expected type `[Char]'
with actual type `IO [Char]'
* In the first argument of `checkIfPathExists', namely
`constructedPath'
In the expression: checkIfPathExists constructedPath
In the expression:
checkIfPathExists constructedPath $ concat' $ paths sample2
我想做這樣的事情:
checksForCdCommand dir = checkIfPathExists constructedPath $ concat' $ paths sample2 where
constructedPath = if currDir /= "/" then currDir "/" dir else currDir dir
其中currDir始終具有檔案中的值。
這個想法是,我有一個表示檔案系統的樹,并且通過 func 路徑,我獲得了所有孩子的路徑,checkIfPathExists我將一個字串作為引數傳遞,以查看它是否是所有路徑的一部分,我正在做一個命令類似于 cd unix 命令,當我更改目錄時,我將當前目錄保存在檔案中。
我需要這個當前目??錄用于其他事情,這就是為什么我需要從檔案中讀取它然后更改變數currDir以便我可以將它用于其他功能。
uj5u.com熱心網友回復:
更改變數 currDir
這是你不能做的事情。其余的都是分散注意力的櫥窗裝飾。如果您的方法從根本上依賴于這樣做,則您需要一種新方法。在某些時候,在 IO 操作中,您需要讀取此abc.txt檔案的內容,并將該結果保存到變數中。然后將該變數(其值不會改變!)傳遞給其他函式。如果在某個時候您想“重繪 ”該變數,則需要重新讀取它并使用該新變數。
例如:
addOneToFileContents :: String -> Maybe (Int, Int)
addOneToFileContents c = case reads c of
[(x, _)] -> Just $ (x, x 1)
_ -> Nothing
main = do
num <- readFile "abc.txt"
case addOneToFileContents num of
Nothing -> putStrLn "abc.txt should contain a number" *> main
Just (x, y) -> putStrLn $ show x " 1 = " show y
這個程式寫得不是很好,但它展示了基本思想。它假設 abc.txt 存在;如果沒有,你會得到一些錯誤。但假設它確實如此,它會非常快速地列印錯誤訊息,直到您(在另一個行程中)修改 abc.txt 以包含一個數字。
您將不得不以類似的方式構建您的程式:一些 IO 操作,可能在main它內部或附近,讀取相關檔案。然后它被傳遞給其他一些函式,該函式根據檔案內容決定要做什么。稍后,您重新讀取檔案main并繼續回圈。
有一些工具可以使這個程序更簡單;例如,您可以使用 Reader 通程序式的純部分來檢測 abc.txt 的內容。孤立地看并沒有真正簡單得多,但它與您可能必須做的其他簿記更干凈地結合在一起,例如通過管道檢查附加 IO 操作的結果。但從根本上沒有什么不同:你必須在 IO 操作中進行 IO,并且變數不會改變。
uj5u.com熱心網友回復:
“我知道變數是不可變的,但有什么辦法可以做到嗎?”
Haskell 對可變變數的主題非常固執——它們不存在,只有不可變的值存在。像多米諾骨牌一樣,一個函式的輸出被連接到下一個函式的輸入中。唯一可變的是開始時輸入的值,以及結束時輸出的值,就像香腸機一樣。可以使用 state monad 或使用資料庫來保存值,但是如果您將檔案用作臨時可變變數,那么這很容易破壞不變性原則。
但是這個“Python”代碼呢?
let file = "abc.txt"
contents <- readFile file
看起來這里發生了可變變數,但這是一種錯覺。這是一種語法糖,Haskell 將其轉換為一系列鏈接的 lambda 運算式。
錯誤訊息是由于您使用了do語法糖引起的:
* Couldn't match expected type `[Char]'
with actual type `IO [Char]'
如果沒有您應該真正提供的型別宣告,Haskell 相信兩件事:
- 使用
doandreturn表示您正在執行IO action, typeIO [Char], where[Char]表示一串文本 - 該定義表示您正在執行文本操作,
concat'因此預期型別是[Char],一個字串
所以,很迷茫。
關于 IO 操作,您需要了解兩件事。
- IO 動作就像 The Golden Goose。正如 Golden Goose 在切開時不包含任何金一樣,因此 IO 操作在切開時不包含您要查找的資料。
- IO 標簽會污染它接觸到的任何東西。因此,正確的做法是撰寫完全不使用 IO 操作的函式,只需將數字轉換為字串,將字串轉換為串列,等等。您將受污染的 IO 操作集中到主函式中。
因此我的建議是:
- 寫一個main函式,包含IO動作
- 在沒有 IO 操作的情況下盡可能多地撰寫其余代碼
- 包括每個函式的型別宣告(它阻止 Haskell 混淆,并允許您檢查自己是否在做正確的事情)
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/400949.html
標籤:哈斯克尔
上一篇:Haskell嵌套函式順序
