Haskell: переписать без явной рекурсии
От: Danila_a Россия http://ib-soft.ru
Дата: 06.04.12 03:20
Оценка:
Есть такая задачка: посчитать расстояние(просто модуль разности) между элементами списка.
Т.е. для [1,5,10] получить [4,9,5].
С явной рекурсией можно сделать так:
allDistances [] acc     = acc
allDistances (x:xs) acc = allDistances xs (acc ++ distances x xs)
                          where distances x ys = map (\y -> abs (x-y)) ys


Можно ли переписать это без использования явной рекурсии?

Вариант через foldl не привел к нужным результатам:

allDistances xs = foldl step [] xs
                  where step ys x = ys ++ distances x xs
                        distances x ys = map (\y -> abs (x-y)) ys

т.к. здесь xs — весь список, а мне нужно хвост при каждом вызове получать.
Re: Haskell: переписать без явной рекурсии
От: Аноним  
Дата: 06.04.12 04:05
Оценка:
  minus x = concat $ zipWith minus' (tails $ tail x) x
  minus' ys x  = zipWith (-) ys (repeat x)
Re: Haskell: переписать без явной рекурсии
От: Vintik_69 Швейцария  
Дата: 06.04.12 04:06
Оценка:
Здравствуйте, Danila_a, Вы писали:


D_>Можно ли переписать это без использования явной рекурсии?


allDistances = (concatMap f).tails 
    where f [] = []
          f (x0:xs) = map (\x -> abs (x - x0)) xs
Re[2]: Haskell: переписать без явной рекурсии
От: nlv  
Дата: 06.04.12 04:13
Оценка:
Здравствуйте, Аноним, Вы писали:


А>
А>  minus x = concat $ zipWith minus' (tails $ tail x) x
А>  minus' ys x  = zipWith (-) ys (repeat x)  
А>


конечно, не (-), а (abs , (-)
Re[3]: Haskell: переписать без явной рекурсии
От: nlv  
Дата: 06.04.12 04:14
Оценка:
пардон

  minus x = concat $ zipWith minus' (tails $ tail x) x
  minus' ys x  = zipWith (abs . (-)) ys (repeat x)
Re[2]: Haskell: переписать без явной рекурсии
От: Danila_a Россия http://ib-soft.ru
Дата: 06.04.12 05:50
Оценка:
Здравствуйте, Vintik_69, Вы писали:

V_>Здравствуйте, Danila_a, Вы писали:



D_>>Можно ли переписать это без использования явной рекурсии?


V_>
allDistances = (concatMap f).tails 
V_>    where f [] = []
V_>          f (x0:xs) = map (\x -> abs (x - x0)) xs
V_>


Да, спасибо. То, что нужно.
Re: Haskell: переписать без явной рекурсии
От: Кодт Россия  
Дата: 06.04.12 10:04
Оценка: +1
Здравствуйте, Danila_a, Вы писали:

D_>Есть такая задачка: посчитать расстояние(просто модуль разности) между элементами списка.

D_>Т.е. для [1,5,10] получить [4,9,5].

Можно изящно (хотя и менее эффективно) сделать на нотации do или list comprehensions
diffs xs =
  do
    let ixs = zip [1..] xs
    i,x <- ixs
    j,y <- ixs
    when (i<j)
    return abs(x-y)

diffs xs = [ abs(x-y) | (i,x) <- ixs, (j,y) <- ixs, (i<j) ] where ixs = zip [1..] xs
Перекуём баги на фичи!
Re: Haskell: переписать без явной рекурсии
От: VoidEx  
Дата: 06.04.12 10:44
Оценка:
Здравствуйте, Danila_a, Вы писали:

D_>Есть такая задачка: посчитать расстояние(просто модуль разности) между элементами списка.

D_>Т.е. для [1,5,10] получить [4,9,5].

Расстояние от 1-го до 3-го элемента есть сумма расстояний от 1-го до 2-го и от 2-го до 3-го. Поэтому задачу можно разбить.
Соответственно:

allDistances l = concat $ map (scanl1 (+)) $ tails $ zipWith subtract l (tail l)


zipWith subtract l (tail l)

Вернёт расстояния между соседними элементами, т.е. для [1,5,10,12,13] -> [4,5,2,1]

Применив к нему tails, получим списки расстояний, начиная с каждого элемента до последнего.
[4,5,2,1]
[5,2,1]
[2,1]
[1]
[]


Применив к каждому scanl1 (+) получим суммарные расстояния:
[4,9,11,12]
[5,7,8]
[2,3]
[1]


Далее соединяем их:
[4,9,11,12,5,7,8,2,3]
Re: Haskell: переписать без явной рекурсии
От: Буравчик Россия  
Дата: 06.04.12 13:32
Оценка: 6 (1)
Здравствуйте, Danila_a, Вы писали:

D_>Есть такая задачка: посчитать расстояние(просто модуль разности) между элементами списка.

D_>Т.е. для [1,5,10] получить [4,9,5].

D_>Можно ли переписать это без использования явной рекурсии?


Вот так еще можно:

allDistances xs = [ abs (x-y)  | (x:ys) <- tails xs, y <- ys ]
... << RSDN@Home (RF) 1.2.0 alpha 5 rev. 17>>
Best regards, Буравчик
Re: Haskell: переписать без явной рекурсии
От: MigMit Россия http://migmit.vox.com
Дата: 07.04.12 05:44
Оценка: :)
Здравствуйте, Danila_a, Вы писали:

D_>Есть такая задачка: посчитать расстояние(просто модуль разности) между элементами списка.

D_>Т.е. для [1,5,10] получить [4,9,5].
D_>С явной рекурсией можно сделать так:
D_>
D_>allDistances [] acc     = acc
D_>allDistances (x:xs) acc = allDistances xs (acc ++ distances x xs)
D_>                          where distances x ys = map (\y -> abs (x-y)) ys
D_>


D_>Можно ли переписать это без использования явной рекурсии?


[y — x | (x:xt) <- tails xs, y <- xt]
Re: Параморфизмы, наконец
От: Аноним  
Дата: 09.04.12 12:59
Оценка:
import Data.Functor.Foldable

allDistances :: Num a => [a] -> [a]
allDistances = para alg where
alg Nil = []
alg (Cons x (xs, tail)) = distances x xs tail

distances x xs tail = cata alg xs where
alg Nil = tail
alg (Cons y xs) = abs (x — y) : xs
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.