在 Haskell 中使用包含在纯函数中的不纯函数的问题
Problem using impure function wrapped in pure function in Haskell
我正在尝试使用包装在纯函数中的 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))
主要的 objective 是获取最接近作为参数传递的给定点的点。
原型必须是这样的:
closest :: FilePath -> (Int, Int, Int) -> (Int, Int, Int)
但我不能使用不纯函数 (readFile),因为该函数不是 IO()。
我该如何解决?
编辑:
- 该文件包含一组 (x,y,z) 格式的点
-距离函数return2个点的距离
-文件可以在任何执行中更改
您已经进入 do
状态;你只是没有利用它。 content
应该从 readFile path
中提取,而不是简单地引用它创建的 IO
操作。您还需要将 return 值更改为 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)
。)
我正在尝试使用包装在纯函数中的 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))
主要的 objective 是获取最接近作为参数传递的给定点的点。 原型必须是这样的:
closest :: FilePath -> (Int, Int, Int) -> (Int, Int, Int)
但我不能使用不纯函数 (readFile),因为该函数不是 IO()。
我该如何解决?
编辑: - 该文件包含一组 (x,y,z) 格式的点
-距离函数return2个点的距离
-文件可以在任何执行中更改
您已经进入 do
状态;你只是没有利用它。 content
应该从 readFile path
中提取,而不是简单地引用它创建的 IO
操作。您还需要将 return 值更改为 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)
。)