我正在嘗試使用包裝在純函式中的 readFile 函式。
使用的函式(在我的學校里,如果我想使用它,我必須重新撰寫所有內置函式)
myNth :: [a] -> Int -> a
myNth [] n = error "error"
myNth (x:xs) 0 = x
myNth (_:xs) n = myNth xs (n - 1)
myTail :: [a] -> [a]
myTail (_:a) = a
myTail [] = error "empty list"
pointStrToInt :: String -> (Int, Int, Int)
pointStrToInt point = (read(myTail(myNth(split ',' point) 0)), read(myNth(split ',' point) 1), read(myNth(split ')' (myNth(split ',' point) 2)) 0))
fileToPointArray :: [String] -> [(Int, Int, Int)]
fileToPointArray = map pointStrToInt
split :: Eq a => a -> [a] -> [[a]]
split d [] = []
split d s = x : split d (drop 1 y) where (x,y) = span (/= d) s
問題功能:
closest :: FilePath -> (Int, Int, Int) -> (Int, Int, Int)
closest path a = do
let content = readFile path
let closestPoint = pointStrToInt (myNth(lines (content)) 0)
--print (closestPoint)
let arr = fileToPointArray (lines content)
--print (arr)
let p = doClosest arr a closestPoint
--print (p)
p
where
doClosest :: [(Int, Int, Int)] -> (Int, Int, Int) -> (Int, Int, Int) -> (Int, Int, Int)
doClosest [] _ a = a
doClosest (x:xs) a (b, c, d) = if ((distance (itofPoint x) (itofPoint a)) < (distance (itofPoint x) (itofPoint (b, c, d))))
then (doClosest xs a x)
else (doClosest xs a (b, c, d))
主要目標是獲取與作為引數傳遞的給定點的最近點。原型必須是這樣的:
closest :: FilePath -> (Int, Int, Int) -> (Int, Int, Int)
但我不能使用不純函式(readFile),因為該函式不是 IO()。
我該如何解決?
編輯:-該檔案包含一組 (x,y,z) 格式的點
-距離函式回傳2個點的距離
-檔案可以在任何執行中更改
uj5u.com熱心網友回復:
你已經陷入do困境;你只是沒有利用它。content應該從 中提取, readFile path而不是簡單地參考IO它創建的動作。您還需要將回傳值更改為IO (Int, Int, Int):
closest :: FilePath -> (Int, Int, Int) -> IO (Int, Int, Int)
closest path a = do
content <- readFile path
let closestPoint = pointStrToInt (myNth(lines (content)) 0)
let arr = fileToPointArray (lines content)
let p = doClosest arr a closestPoint
return p
where
doClosest :: [(Int, Int, Int)] -> (Int, Int, Int) -> (Int, Int, Int) -> (Int, Int, Int)
doClosest [] _ a = a
doClosest (x:xs) a (b, c, d) = if ((distance (itofPoint x) (itofPoint a)) < (distance (itofPoint x) (itofPoint (b, c, d))))
then (doClosest xs a x)
else (doClosest xs a (b, c, d))
更簡單一點的是保持closest純凈并將其與readFile包裝器結合。
-- Note the order of arguments is reversed, so that we
-- can partially apply it later...
closest :: (Int, Int, Int) -> String -> (Int, Int, Int)
closest content a = let closestPoint = pointStrToInt (myNth(lines (content)) 0)
arr = fileToPointArray (lines content)
in doClosest arr a closestPoint
where
doClosest :: [(Int, Int, Int)] -> (Int, Int, Int) -> (Int, Int, Int) -> (Int, Int, Int)
doClosest [] _ a = a
doClosest (x:xs) a (b, c, d) = if ((distance (itofPoint x) (itofPoint a)) < (distance (itofPoint x) (itofPoint (b, c, d))))
then (doClosest xs a x)
else (doClosest xs a (b, c, d))
doIt :: FilePath -> (Int, Int, Int) -> IO (Int, Int, Int)
doIt path a = fmap (closest a) (readFile path)
(如果您不想或無法更改 中的引數順序closest,則可以fmap (flip closest a) (readFile path)改用。)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/462861.html
上一篇:HaskellmapM_不列印
下一篇:基于范數約束向量的型別
