2015-06-17 2 views
1

Я новичок в Haskell и функционального программирования в целом, так что я не знаю, как сделать этот код идиоматическое:Идиоматические список строительства

type Coord = Double 
data Point = Point Coord Coord Coord deriving Show 

type Polyline = [Point] 

-- Add a point to a polyline 
addPoint :: Polyline -> Point -> Polyline 
addPoint line p = p:line 

line :: Polyline 
line = [] 

constructLine :: Polyline -> Polyline 
constructLine line = 
    let 
     p1 = Point 2 4 87 
     p2 = Point 3 7 2 
     p3 = Point 23 4 8 
    in addPoint (addPoint (addPoint line p1) p2) p3 

main :: IO() 
main = do 
    putStrLn (show (constructLine line)) 

Моя проблема заключается в функции constructLine. Если я хочу добавить много точек, то вложенные функции addPoint будут проблемой. Как я могу это учитывать? И видите ли вы другие вещи, которые можно было бы улучшить?

+0

Предоставить функцию, которая задает список точек, создает полилинию. Например, вы можете использовать 'addPoints line ps = ps ++ line' или что-то в этом роде. BTW: вы также можете вызвать 'addPoint' в нотации infix. – Bakuriu

+1

Идиоматическим способом, вероятно, было бы ditch 'addPoint' и просто построить список непосредственно как' [p3, p2, p1] ', но если вы хотите сохранить этот реферат, просто создайте свой собственный оператор, например' infixr 5 # ' , '(#) :: Point -> Polyline -> Polyline',' (#) = addPoint' (обратите внимание, что я поменял порядок аргументов здесь). Линия 'infixr' важна, убедитесь, что вы ее сохранили, но это означает, что вы могли бы написать это как« p3 # p2 # p1 # line'. Если вы действительно хотите сохранить порядок аргументов, тогда сделайте 'infixl 5 #', и вместо этого он будет написан как 'line # p1 # p2 # p3'. – bheklilr

+1

Обратите внимание, что если вы изменили порядок аргументов так, чтобы это было 'addPoint :: Point -> Polyline -> Polyline', вы можете написать это как' addPoint p3 $ addPoint p2 $ addPoint p1 line', чего может быть достаточно для вашего цели. – bheklilr

ответ

5

Многократный вызов addPoints может быть заменен на складку. Как было отмечено в комментарии, обращая ваши функции addPoint бы сделать вещи проще:

addPoint' :: Point -> Polyline -> Polyline 
addPoint' p line = p:line 

Итак ваша функция constructLine может построить временный список точек, чтобы добавить добавить Используйте складку:

constructLine :: Polyline -> Polyline 
constructLine line = 
    let 
     p1 = Point 2 4 87 
     p2 = Point 3 7 2 
     p3 = Point 23 4 8 
    in foldr addPoint' line [p3,p2,p1] 

Это не прерывает инкапсуляцию (вы можете заменить вашу реализацию Полилины чем-то другим, чем список Точки) и использует новые точки в том порядке, в котором они будут заканчиваться (p3 перед p2 и т. д.)

2

Ваш constructLine экзамен е просто поражает меня как многословно версии этого:

constructLine :: Polyline -> Polyline 
constructLine line = [Point 23 4 8, Point 3 7 2, Point 2 4 87] ++ line 

Я не знаю, если вы столкнетесь с этим еще, но только, чтобы быть уверенным:

  • [Point 23 4 8, Point 3 7 2, Point 2 4 87] просто list literal.
  • ++ - это функция добавления списков.

Как правило, чтобы добавить несколько элементов в список, то, что вы делаете, есть список элементов, которые вы хотите добавить, и добавьте этот список вместе с исходным списком.

Этот шаблон продолжается. Если мы замечаем, что line константа определяется [], то вся ваша программа на самом деле это просто многословно версия этого:

type Coord = Double 
data Point = Point Coord Coord Coord deriving Show 

main :: IO() 
main = putStrLn (show points) 
    where points = [Point 23 4 8, Point 3 7 2, Point 2 4 87] 

В принципе, если значения точек известны во время компиляции, вы можете просто напишите список, вам не нужно проходить через все это косвенное направление.

+0

Да, я знаю это, но я хотел бы абстрагироваться от построения полилинии. Спасибо за ваш ответ! –

+0

@ElieGnrd: Если полилинии концептуально похожи на списки, но есть инварианты, которые вы хотите защитить, один простой способ состоит в том, чтобы иметь функции преобразования обратно и вперед между непрозрачным типом «PolyLine» и списками точек. Тогда много логики может быть сделано в терминах операций с списками (очень хорошо поддерживается в Haskell), и для создания «PolyLine» вы просто поставляете список. Например, тип 'Data.Map.Map' в платформе Haskell работает так: один из наиболее распространенных способов его создания - использовать функцию' fromList :: Ord k => [(k, v)] - > Карта kv'. –

Смежные вопросы