映射应用于Haskell中的多个参数

时间:2010-03-01 21:58:39

标签: haskell functional-programming

有没有办法使用Haskell的“map”或类似的多个参数?

即。找到给定点(定义为元组)与其他点列表之间的距离:

map distance (-3,-3) buildings

显然,这不起作用,因为它试图将“距离”映射到(-3,-3),其中距离需要两个元组:

let distance pointA pointB = sqrt ( (frst pointB - frst pointA) * (frst pointB - frst pointA) + (scnd pointB - scnd pointA) * (scnd pointB - scnd pointA) )

距离需要两个点作为参数:在本例中,一个是(-3,-3),一个是从“建筑物”列表中选择的。

( - 3,-3)只是一个例子。这必须是一个变量;它不能硬编码到函数中。

也许这会更有意义:

buildings = [(3,-2),(2,1),(5,3),(4,3),(4,-1)]

firstDiff pointA pointB = subtract ( fst pointA ) ( fst pointB )

secondDiff pointA pointB = subtract ( snd pointA ) ( snd pointB )

distance pointA pointB = sqrt ( (firstDiff pointA pointB) * (firstDiff pointA pointB) +     (secondDiff pointA pointB) * (secondDiff pointA pointB))

--- What I need to happen here is a list "score" to be created by taking all distances from a point in a list lPoints to a point in list buildings.

5 个答案:

答案 0 :(得分:19)

allDistances src dests = map (\point -> distance src point) dests

allDistances src dests = map (distance src) dests

allDistances src = map (distance src)

allDistances = map . distance

答案 1 :(得分:11)

你想要:

map (distance (-3, -3)) buildings

map f buildings 
  where f = distance (-3, -3)  

答案 2 :(得分:2)

在看到对ja回复的评论后,我猜你想使用zipWith

Prelude>:type zipWith
zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]

documentation州:

  

zipWith通过使用作为第一个参数给出的函数进行压缩来进行压缩,而不是使用tupling函数。例如,zipWith(+)应用于两个列表以生成相应总和的列表。

所以在上面的代码中,这可能看起来像:

Prelude> let dist a b = sqrt ( (fst b - fst a) * (fst b - fst a) + (snd b - snd a) * (snd b - snd a) )
Prelude> let buildings = [(1.0,1.0 ), (3.0,3.0 ), (4.0,4.0)]
Prelude> let points = [ (1.2, 2.23), (2.23, 34.23), (324.3, 34.3) ]
Prelude> zipWith dist points buildings
[1.2461540835707277,31.239491032985793,321.7299799521332]

答案 3 :(得分:0)

distance (x, y) (z, w) = sqrt $ (x - z) ^ 2 + (y - w) ^ 2

func1 = map . distance

func2 starts ends = starts >>= flip func1 ends

func1是你描述的函数,而func2是相似的,但是接受多个起点而不是一个,并找到每个组合与终点之间的距离。

答案 4 :(得分:0)

距离公式很简单:

distance :: Floating a => (a,a) -> (a,a) -> a
distance (x1,y1) (x2,y2) = sqrt $ (x2 - x1)^2 + (y2 - y1)^2

请注意使用模式匹配来分解参数,而不是使用fstsnd乱丢代码。

然后

从给定点到列表中所有点的相应距离
distanceFrom :: Floating a => (a,a) -> [(a,a)] -> [a]
distanceFrom p = map (distance p)

虽然参数似乎缺失,但在Haskell中称为partial application。在distanceFrom中,我们有两个:

  1. distance p是一个点的函数,其值是该点距p的距离
  2. map (distance p)是一个点列表的函数,其值是这些点与p的距离
  3. 尝试将Haskell函数设计为部分应用程序,以便将小函数组合成更大的函数。如ephemient's answer中所述,您可以进一步推进pointfree定义(没有明确的参数) - 更优雅,更先进的风格。

    buildings中距lPoints中所有点的距离{/ 1}}

    main :: IO ()
    main = do
      mapM_ (putStrLn . unwords . map (printf "%6.3f")) score
      where
        score = [ distanceFrom x buildings | x <- lPoints ]
    

    例如,使lPointsbuildings相等,输出为

     0.000  3.162  5.385  5.099  1.414
     3.162  0.000  3.606  2.828  2.828
     5.385  3.606  0.000  1.000  4.123
     5.099  2.828  1.000  0.000  4.000
     1.414  2.828  4.123  4.000  0.000

    但考虑到所有的冗余,在这种特殊情况下,这有点无聊。要改为打印strict upper triangle,请使用

    strictUpperTriangle :: [[a]] -> [[a]]
    strictUpperTriangle [] = []
    strictUpperTriangle xs = go (init xs)
      where go (x:xs) = tail x : map tail (go xs)
            go [] = []
    
    printSUT :: PrintfArg a => [[a]] -> IO ()
    printSUT sut = putStr (unlines $ map pad sut)
      where n = length sut
            pad xs = let k = n - length xs in
                     unwords $ take k blanks ++ map (printf "%*.3f" w) xs
            blanks = repeat (take w $ repeat ' ')
            w = 6 :: Int
    
    main :: IO ()
    main = printSUT tri
      where
        score = [ distanceFrom x buildings | x <- lPoints ]
        tri = strictUpperTriangle score
    

    输出:

     3.162  5.385  5.099  1.414
            3.606  2.828  2.828
                   1.000  4.123
                          4.000