我正在尝试解决Haskell中的竞争性编程挑战问题.
这是我的代码:
module Main (main) where
import System.IO
import Text.Printf
getInt :: IO Int
getInt = readLn
getDouble :: IO Double
getDouble = readLn
getCoordinate :: (IO Double, IO Double, IO Double)
getCoordinate = (getDouble, getDouble, getDouble)
readCoordinates :: Int -> [(IO Double, IO Double, IO Double)] -> [(IO Double, IO Double, IO Double)]
readCoordinates 0 list = list
readCoordinates a list = readCoordinates (a - 1) list ++ [getCoordinate]
main :: IO ()
main = do
limit <- getInt
coordinates <- (readCoordinates limit [])
printf "%.2f\n" (run 0.0 (head coordinates) (tail coordinates))
run :: Double -> (Double, Double, Double) -> [(Double, Double, Double)] -> Double
run curr c1 (c2:cs) = run (curr + (d c1 c2)) c2 cs
run curr c1 [] = curr
d :: (Double, Double, Double) -> (Double, Double, Double) -> Double
d (x1, y1, z1) (x2, y2, z2) = sqrt (sas x1 x2) + (sas y1 y2) + (sas z1 z2)
sas :: Double -> Double -> Double
sas a1 a2 = (a1 - a2) ** 2
Run Code Online (Sandbox Code Playgroud)
所以你可能会猜到我正在读一个整数,它表示我应该读入多少3d坐标.然后我尝试读取所有这些并计算距离.
我收到很多错误,这里是错误日志:
Akvariet.hs:22:19:
Couldn't match type `[]' with `IO'
Expected type: IO (IO Double, IO Double, IO Double)
Actual type: [(IO Double, IO Double, IO Double)]
In the return type of a call of `readCoordinates'
In a stmt of a 'do' block:
coordinates <- (readCoordinates limit [])
In the expression:
do { limit <- getInt;
coordinates <- (readCoordinates limit []);
printf "%.2f" (run 0.0 (head coordinates) (tail coordinates)) }
Akvariet.hs:23:34:
Couldn't match expected type `[(Double, Double, Double)]'
with actual type `(IO Double, IO Double, IO Double)'
In the first argument of `head', namely `coordinates'
In the second argument of `run', namely `(head coordinates)'
In the second argument of `printf', namely
`(run 0.0 (head coordinates) (tail coordinates))'
Akvariet.hs:23:53:
Couldn't match expected type `[(Double, Double, Double)]'
with actual type `(IO Double, IO Double, IO Double)'
In the first argument of `tail', namely `coordinates'
In the third argument of `run', namely `(tail coordinates)'
In the second argument of `printf', namely
`(run 0.0 (head coordinates) (tail coordinates))'
Run Code Online (Sandbox Code Playgroud)
我实际上无法真正地围绕IO类型,我知道它是不纯的并且每次都不会返回相同的东西,但我如何在我的程序中使用它?
我不明白readCoordinates方法如何编译以及为什么当main仍然是类型时它无法将IO Double转换为Double IO ().
干杯!
首先,我建议你不要读数,然后单独输入每个坐标.一次性读取所有输入(产生一个字符串)更容易,然后将其解析为坐标,而不必担心它是如何来自IO的.这看起来像
main = do
allInput <- getContents
let coordinates = parseCoords $ lines allInput
printf ...
Run Code Online (Sandbox Code Playgroud)
同
type Vect = (Double, Double, Double)
parseCoords :: [String] -> [Vect]
parseCoords (x:y:z:cs) = (read x, read y, read z) : parseCoords cs
parseCoords _ = []
Run Code Online (Sandbox Code Playgroud)
如果您希望手动阅读所有内容,以便精确控制订单或其他任何内容,那么您需要正确使用IOmonad.将三个getDoubles 组合成IO动作元组几乎没有用处; 你真正想要的是一个单一的 IO操作这将产生一个纯粹的坐标元组.
getCoordinate :: IO Vect
getCoordinate = do
x <- getDouble
y <- getDouble
z <- getDouble
return (x,y,z)
Run Code Online (Sandbox Code Playgroud)
实际上这可以用Applicative写得更好,但我怀疑你发现上面的do写作更容易理解:
getCoordinate' = liftA3 (,,) getDouble getDouble getDouble
Run Code Online (Sandbox Code Playgroud)