Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
List 尝试从Haskell中的数据类型列表创建字符串列表_List_Haskell - Fatal编程技术网

List 尝试从Haskell中的数据类型列表创建字符串列表

List 尝试从Haskell中的数据类型列表创建字符串列表,list,haskell,List,Haskell,我试图获取一个数据类型列表(多边形),对每个多边形(calcPerim)执行一个操作,该操作返回一个(Double,Double)。然后我将其转换为字符串(lengthsToString)。我想要一个包含所有这些字符串的列表 import System.IO import Data.List import Text.Printf type Point = (Double, Double) type Segment = (Point, Point) type Length = Double d

我试图获取一个数据类型列表(多边形),对每个多边形(calcPerim)执行一个操作,该操作返回一个(Double,Double)。然后我将其转换为字符串(lengthsToString)。我想要一个包含所有这些字符串的列表

import System.IO
import Data.List
import Text.Printf

type Point = (Double, Double)
type Segment = (Point, Point)
type Length = Double

data Polygon = Polygon { vertices :: Int
                       , yline :: Double
                       , points :: [Point]
                       } deriving (Show)

main = do  
    let list = []
    handle <- openFile "polycake.in" ReadMode
    contents <- hGetContents handle
    let singlewords = words contents
        list = fileToList singlewords
        n = list!!0
        list' = drop 1 list
        polygons = polyList n list'  
        output = outList polygons n
    print (output)
    hClose handle 


outList :: [Polygon] -> Int -> [String]
outList polygons i =
    if i < length polygons
        then
            let polygon = polygons!!i
                perim = calcPerim (yline polygon) (points polygon)
                perim' = fromJust perim
                lenString = lengthsToString perim'
                nextString = outList polygons (i+1)
            in (lenString:nextString)
    else []


show3Decimals :: Double -> String
show3Decimals x = printf "%.3f" x

lengthsToString :: (Double, Double) -> String
lengthsToString (min, max) = show3Decimals min ++ " " ++ show3Decimals max

maxLength :: (Length, Length) -> Length
maxLength (a, b) =
    if a > b
        then a
        else b

minLength :: (Length, Length) -> Length
minLength (a, b) =
    if a < b
        then a
        else b

--unwraps value from Just
fromJust :: Maybe a -> a
fromJust Nothing  = error "Maybe.fromJust: Nothing"
fromJust (Just x) = x

--function to convert file to a list of Ints
--In: list of strings
--Out: list of Ints
fileToList :: [String] -> [Int]
fileToList = map read

--function to create a list of Polygon data types
--In: # of test cases, list containing test case data
--Out: list of Polygons
polyList :: Int -> [Int] -> [Polygon]
polyList n [] = []
polyList _ [x] = error "Too few points remaining"
polyList n (v:y:list') =
    let pointList = take (2*v) list' -- Note: list' may not *have* 2*v points
        points = getPoints pointList
        list'' = drop (2*v) list'
        poly = Polygon { vertices = v, yline = fromIntegral y, points = points}
        nextPoly = polyList (n-1) list''
    in (poly:nextPoly)

--function to convert a list of ints, into a list of tuples containing 2 Doubles
--In: list of ints
--Out: list of Points
getPoints :: [Int] -> [Point]
getPoints [] = []
getPoints (k:v:t) = (fromIntegral k, fromIntegral v) : getPoints t



-- Check whether a segment is over, under or on the line given by y
segmentCompare :: Double -> Segment -> Ordering
segmentCompare y (p,q) =                                                                          
    case () of                                                                                        
        _ | all (`isUnder` y) [p,q] -> LT
        _ | all (`isOver` y)  [p,q] -> GT
        _ -> EQ



-- Partition a list into (lt, eq, gt) based on f
partition3 :: (Segment -> Ordering) -> [Segment] -> ([Segment], [Segment], [Segment])
partition3 f = p' ([], [], [])
  where
    p' (lt, eq, gt) (x:xs) =
        case f x of
            LT -> p' (x:lt, eq, gt) xs
            EQ -> p' (lt, x:eq, gt) xs
            GT -> p' (lt, eq, x:gt) xs
    p' result [] = result



-- Split a crossing segment into an under part and over part, and return middle
divvy :: Double -> Segment -> (Segment, Segment, Point)
divvy y (start, end) =
    if start `isUnder` y
    then ((start, middle), (middle, end), middle)
    else ((middle, end), (start, middle), middle)
  where
    middle = intersectPoint y (start, end)



-- Split a polygon in two, or Nothing if it's not convex enough
splitPolygon :: Double -> [Point] -> Maybe ([Segment], [Segment])
splitPolygon y list = do
    let (under, crossing, over) = partition3 (segmentCompare y) pairs
    case crossing of
        -- No lines cross. Simple.
        [] -> return (under, over)
        -- Two segments cross. Divide them up.
        [(p1,p2),(q1,q2)] ->
            let (u1, o1, mid1) = divvy y (p1,p2)
                (u2, o2, mid2) = divvy y (q1, q2)
                split = (mid1, mid2) :: Segment
            in return (split:u1:u2:under, split:o1:o2:over)
        -- More segments cross. Algorithm doesn't work.
        rest -> fail "Can't split polygons concave at y"
  where
    pairs = zip list (drop 1 $ cycle list) :: [Segment]



-- 
calcPerim :: Double -> [Point] -> Maybe (Length, Length)
calcPerim y list = do
    (under, over) <- (splitPolygon y list :: Maybe ([Segment], [Segment]))
    return (sumSegments under, sumSegments over)



-- Self explanatory helpers
distance :: Segment -> Length
distance ((ax, ay), (bx, by)) = sqrt $ (bx-ax)^2 + (by-ay)^2

intersectPoint :: Double -> Segment -> Point
intersectPoint y ((px, py), (qx, qy)) =
    let t = (y-py)/(qy-py)
        x = px + t * (qx - px)
    in
        (x,y)


sumSegments :: [Segment] -> Length
sumSegments = sum . map distance

isUnder :: Point -> Double -> Bool
isUnder (_, py) y = py < y
isOver (_, py) y = py > y
样本输出:

12.000 12.000
25.690 35.302
17.071 27.071

主要的问题是在outList函数中,因为我已经测试了其他所有内容,现在我只想将输出放入一个列表中,以便以非常确定的方式将其打印出来。因为我需要通过在程序输出和给定输出之间进行“差异”来通过测试用例。

首先,您当前的方法不是编写Haskell的最佳方法。很容易把事情搞砸。让我们试着后退一点。 您说过要“对每个多边形执行操作”。这就是函数的作用

看看类型签名:

map :: (a -> b) -> [a] -> [b]
在您的情况下,
a
将是一个
多边形
b
将是一个
字符串
。所以map函数将接受一个函数和一个多边形列表,并返回一个字符串列表,这就是您想要的

但是,您需要使用一些函数组合以及lambda来创建一个函数,该函数采用
多边形
,并输出
字符串
。 下面是一个可能的示例,说明您可以做什么:

outList :: [Polygon] -> [String]
outList polygons = map (\poly -> lengthsToString . fromJust $
                                 calcPerim (yline poly) (points poly)) polygons

一般来说,您应该尽量避免Haskell中的显式递归,而是使用Prelude函数来完成您需要的工作。与手动操作相比,它还提供了更干净、更清晰和更短的代码。

您能解释一下\poly->部分吗?(yline多边形)应该是(yline多边形)吗?poly是列表中的当前多边形吗?我得到一个错误:无法将预期类型“[String]”与实际类型“[polygon]->[String]”匹配抱歉,我在手机上编写了该代码,因此无法编译它。关于命名问题,你是对的。此外,我忘了将贴图应用到
多边形
列表。我认为代码现在应该可以工作了。您能简化您的示例并更清楚地说明问题所在吗:
outList
是否引发某种运行时错误?它没有通过打字检查吗?(发布错误消息)或者它只是不能正常工作(它应该做什么)?它只是返回一个空列表,所以我假设它只是立即跳转到else,不需要假设。如果
outList
返回
[]
,那么您可以确定它的参数是什么?听起来您需要更仔细地考虑在
main
中调用
outList
的站点。
outList :: [Polygon] -> [String]
outList polygons = map (\poly -> lengthsToString . fromJust $
                                 calcPerim (yline poly) (points poly)) polygons