Loops 记忆旧数据
记住你的第一次(在Haskell循环中) 我试着通过一些黑客问题来教自己一点哈斯克尔 我正在研究的问题涉及以坐标(x1,y1)和(x2,y2)和 确定由这些坐标绘制的多边形的周长 以下是我目前的代码:Loops 记忆旧数据,loops,haskell,state,Loops,Haskell,State,记住你的第一次(在Haskell循环中) 我试着通过一些黑客问题来教自己一点哈斯克尔 我正在研究的问题涉及以坐标(x1,y1)和(x2,y2)和 确定由这些坐标绘制的多边形的周长 以下是我目前的代码: -- Calculate length of line given points x1,y2, x2,y2 calc_length:: Int -> Int -> Int -> Int -> Float calc_length x1 y1 x2 y2 = s
-- Calculate length of line given points x1,y2, x2,y2
calc_length:: Int -> Int -> Int -> Int -> Float
calc_length x1 y1 x2 y2 =
sqrt ( fromIntegral (height ^2 + width ^2) )
where height = abs( y2 - y1)
width = abs( x2 - x1)
main = do
x <- readLn :: IO Double
forM_ [1,2..(x / 2)] $ \lc -> do
line1 <- getLine
let wds1 = map (\str -> read str::Int) (words $ line1)
line2 <- getLine
let wds2 = map (\str -> read str::Int) (words $ line2)
print ( wds1, wds2)
——计算给定点x1、y2、x2、y2的直线长度
计算长度::Int->Int->Int->Int->Int->Float
计算长度x1 y1 x2 y2=
sqrt(从整数(高度^2+宽度^2))
其中高度=绝对值(y2-y1)
宽度=绝对值(x2-x1)
main=do
x do
第1行读取str::Int(单词$line1)
第2行读取str::Int)(单词$line2)
打印(wds1、wds2)
我的问题是,我需要计算第一个坐标和最后一个坐标之间的距离,即记住输入的第一对数字(存储在第1行)。但在乘法迭代之后,第一对将丢失。我曾尝试使用全局变量存储getLine的第一次调用(几乎没有成功,即使成功了,我也不认为这会有帮助)
我觉得有一种更实用的方法我可以尝试,但就是不知道怎么做
我不是在寻找一个完整的编码解决方案,只是一种能为我指明更好方向的方法
有什么想法吗?如果您需要以不同的方式对待第一次迭代,应该将其分开(如果我正确理解您的问题)。您可以使用辅助功能减少重复:
getNumLine :: IO [Int]
getNumLine = do
line <- getLine
return (map read (words line))
main = do
x <- readLn :: IO Int -- Double seemed wrong, use integer `div` below instead
firstline <- getNumLine
forM_ [2..x `div` 2] $ \lc -> do
...
getNumLine::IO[Int]
getNumLine=do
line您要求提供一种更实用的方式来思考这个问题,所以我将尝试提供这一点。你说你是Haskell的新手,所以如果这涉及到你还没有探索的东西,我提前道歉。请随时要求澄清其中的任何部分
首先,让我们对calcLength
函数进行更多的分段。我们传递了两个点,所以与其传递四个参数,不如只传递两个
data Point a = Point a a
calcLength :: Floating a => Point a -> Point a -> a
calcLength (Point x1 y1) (Point x2 y2) = sqrt (height ^ 2 + width ^ 2)
where height = abs (y2 - y1)
width = abs (x2 - x1)
现在,让我们编写一个读取单个点的函数。我们将从main
调用它,而不是在main
中分别读取两个数值
readPoint :: (Floating a, Read a) => IO (Point a)
readPoint = Point <$> readLn <*> readLn
newtype Polygon a = Polygon [Point a]
perimeter :: Floating a => Polygon a -> a
perimeter (Polygon xs) = sum . map (\(a, b) -> calcLength a b) $ loopedPairs xs
现在我们将编写一个周长函数。将尽可能多的“纯”非IO逻辑从IO工作中分离出来是很好的,因此我们希望将其从main
中分离出来
readPoint :: (Floating a, Read a) => IO (Point a)
readPoint = Point <$> readLn <*> readLn
newtype Polygon a = Polygon [Point a]
perimeter :: Floating a => Polygon a -> a
perimeter (Polygon xs) = sum . map (\(a, b) -> calcLength a b) $ loopedPairs xs
我们取一个多边形,它实际上只是一个点列表,使用loopedPairs
将所有点配对,然后计算每个点之间的长度,并将结果相加
考虑到这一点,main
相当短
main :: IO ()
main = do
n <- readLn :: IO Int
points <- replicateM n (readPoint :: IO (Point Double))
let result = perimeter (Polygon points)
print result
我请你仔细分析一下,如果你有任何问题,请告诉我。函数式编程是一种很难掌握的思维方式,因为它与其他编程非常不同,但它是一套方便的技术,可以放在您的工具带中。Everbody帮助后:我的最终解决方案:
import Control.Monad
data Point a = Point a a
newtype Polygon a = Polygon [Point a]
calcLength :: Floating a => Point a -> Point a -> a
calcLength (Point x1 y1) (Point x2 y2) = sqrt (height ^ 2 + width ^ 2)
where height = abs (y2 - y1)
width = abs (x2 - x1)
readPoint :: (Floating a, Read a) => IO (Point a)
readPoint = Point <$> readLn <*> readLn
loopedPairs :: [a] -> [(a, a)]
loopedPairs [] = []
loopedPairs (x:xs) = go x xs
where go x' (y:ys) = (x', y) : go y ys
go x' [] = [(x', x)]
perimeter :: Floating a => Polygon a -> a
perimeter (Polygon xs) = sum . map (\(a, b) -> calcLength a b) $ loopedPairs xs
main :: IO ()
main = do
n <- readLn :: IO Int
points <- replicateM n (readPoint :: IO (Point Double))
let result = perimeter (Polygon points)
print result
import Data.List
import Data.Foldable
import Data.Traversable
import Data.List.Split
-- Calculate length of line given points x1,y2, x2,y2
calc_length:: Int -> Int -> Int -> Int -> Float
calc_length x1 y1 x2 y2 =
sqrt ( fromIntegral (height ^2 + width ^2) )
where height = abs( y2 - y1)
width = abs( x2 - x1)
-- Calculate the distances between vertex points (except the last)
getResults list =
sum [ calc_length (head f) (last f) (head s) (last s) | (f,s) <- (zip list (tail list)) ]
-- Calculate the last vertex distance between points
headAndTail list =
calc_length (z!!0) (z!!1) (z!!2) (z!!3)
where z = head list ++ last list
-- Prompt the user for co-ordinate pairs
main = do
x <- readLn :: IO Double
result <- forM [1,2..x ] ( \lc -> do
line1 <- getLine
let wds1 = map (\str -> read str::Int) (words $ line1)
return wds1)
print ( (getResults result) + (headAndTail result) )
导入数据。列表
导入数据。可折叠
导入数据。可遍历
导入Data.List.Split
--计算给定点x1、y2、x2、y2的直线长度
计算长度::Int->Int->Int->Int->Int->Float
计算长度x1 y1 x2 y2=
sqrt(从整数(高度^2+宽度^2))
其中高度=绝对值(y2-y1)
宽度=绝对值(x2-x1)
--计算顶点之间的距离(最后一个顶点除外)
getResults列表=
求和[calc_length(head f)(last f)(head s)(last s)|(f,s)为什么不把所有坐标存储在一个列表中呢?只需将表单
更改为表单
,将打印
更改为返回
。嗨,梅尔波梅,好的,看起来我需要调查表单与表单的对比-我看到表单可以让我记住结果,而表单不需要。西尔维奥,感谢你花时间提供真正全面的回复。感谢你的努力。我是我相信我可以从你的代码中学到很多东西。我会花一些时间看看。