2010-03-01 19 views
8

有沒有辦法使用Haskell的「地圖」或類似的多個參數?在Haskell中應用於多個參數的地圖

即發現和其他點的列表給定的點(定義爲一個元組)之間的距離:

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. 

回答

10

你想:

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

這是

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

距離取兩個點作爲參數:一個是(-3,-3)在這個例子中,和一個從該列表「中選擇建築」。 012- (-3,-3)只是一個例子。這必須是一個變量;它不能被硬編碼到函數中。 – 2010-03-01 22:10:11

+2

顯然「地圖(距離第一點)建築物」將工作,不是嗎?或者直截了當地說:「從建築物建築物=地圖(距離點)建築物」 – ondra 2010-03-01 22:21:29

+0

當然,你可以用一個變量代替(-3,-3)。 – helium 2010-03-01 22:25:33

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 
+2

尼斯扣沒有一點點的形式 – 2010-03-01 22:29:09

2

看到在JA的迴應我的評論後估計你想用zipWith

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

documentation狀態:

zipWith通過用給定的作爲第一個參數的函數壓縮和解可以推廣代替幾倍功能拉鍊。例如,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] 
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是相似的,但在多重啓動點,而不是隻取一個,發現了每個組合與終點之間的距離。

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

嘗試設計您的Haskell函數的部分應用程序,以便輕鬆地將小函數組合成更大的函數。如ephemient's answer中所述,您可以進一步獲得pointfree定義(無明確參數) - 更優雅,更高級的風格。

到每個點在buildings從所有點在lPoints的距離然後

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
+0

我不明白這是什麼意思?這只是多餘的,如果lPpoints和建築物是平等的 – 2010-03-02 05:03:13

+0

@trinithis在我的腦海中的「在這種情況下」沒有讓我的答案。謝謝並編輯! – 2010-03-02 15:00:24