juan_gandhi: (Default)
Juan-Carlos Gandhi ([personal profile] juan_gandhi) wrote2010-01-29 08:30 pm

how to say in Haskell...


pairwise :: [a] →  [(a, a)]
pairwise [] = []
pairwise (x:y:rest) = (x,y) : pairwise rest

is there something that does it already? Could not figure out.

[identity profile] permea-kra.livejournal.com 2010-01-30 06:25 am (UTC)(link)
No, there is no standard way to do such things, i.e. there is no famous functions in base libraries that does something alike. You can build your one primitives to work with lists, however. Parser combinators library like ReadP is a good start point.

[identity profile] rinver.livejournal.com 2010-01-30 06:42 am (UTC)(link)
Наверное так. Но что если этой функции подать список из нечётного количества элементов ? :) Или нефиг ? :)

[identity profile] nivanych.livejournal.com 2010-01-30 12:19 pm (UTC)(link)
Надо было добавить что-нибудь, вроде
pairwise (x:[]) = [(x,x)] или []
Без подобного паттерн получается неполным.

[identity profile] http://users.livejournal.com/_navi_/ 2010-01-30 07:23 am (UTC)(link)
Nothing standard comes to my. There's a problem with your code btw: pairwise is not tail-recursive and will blow up the stack.

[identity profile] huzhepidarasa.livejournal.com 2010-01-30 09:58 am (UTC)(link)
а как сделать tail-recursive чтобы не разворачивало список?

[identity profile] huzhepidarasa.livejournal.com 2010-01-30 10:03 am (UTC)(link)
нет, что-то не то — pairwise [1..] прекрасно работает, никакого переполнения стека не происходит.

[identity profile] faceted-jacinth.livejournal.com 2010-01-30 10:47 am (UTC)(link)
Это потому что она ещё и ленивая. pairwise 1:2:3 = (1, 2) : (pairwise [3]), на стеке ничего нет.

Точно так же foldr может спокойно сворачивать бесконечные списки ничего не переполняя.

[identity profile] huzhepidarasa.livejournal.com 2010-01-30 12:38 pm (UTC)(link)
не совсем так

*Main> foldr (+) 0 [1..]
*** Exception: stack overflow
*Main> sum [1..]
(комп намертво зависает, считая расходящуюся сумму, но переполнения не происходит)


foldr может сворачивать бесконечные списки только при наличии определенных оптимизаций, а в интерактивном режиме они отключены. sum же скомпилирована уже с оптимизациями и поэтому ничего не переполняет.

[identity profile] faceted-jacinth.livejournal.com 2010-01-30 12:55 pm (UTC)(link)
Да нет же. Это у вас (+) стековерфловится, а не фолдр. length (foldr (:) [] (take 10000000 [1..])) замечательно считается и в интерактивном режиме тоже, например.

Посмотрите на определение foldr, нет там никакой рекурсии. А (+) точно так же и foldl оверфловнет -- потому что он на самом деле ничего не вычисляет, а строит огромное дерево термов, при попытке которого и случается SO.

[identity profile] faceted-jacinth.livejournal.com 2010-01-30 12:56 pm (UTC)(link)
* при попытке вычислить значение которого

[identity profile] huzhepidarasa.livejournal.com 2010-01-30 01:37 pm (UTC)(link)
а, ну да, в общем понятно. только где такое определение foldr, чтобы без рекурсии?

[identity profile] faceted-jacinth.livejournal.com 2010-01-30 01:44 pm (UTC)(link)
Ну, я имею в виду, что сам фолдр не вычисляется рекурсивно -- не использует стек. Стек может использовать то, что его вызывает, или переданная ему функция, а сам фолдр (так же, как и pairwise) лениво и нерекурсивно идёт по списку слева-направо, не тратя никакой дополнительной памяти.

foldr f x0 x:xs = f x (foldr f x0 xs)
foldr f x0 [] = x0

[identity profile] huzhepidarasa.livejournal.com 2010-01-30 04:27 pm (UTC)(link)
ну, если считать, что рекурсивно — это со стеком, то да

[identity profile] alexey-rom.livejournal.com 2010-01-30 03:37 pm (UTC)(link)
It isn't tail-recursive, but it is bounded-recursive (all recursive calls are under data constructors), which is more relevant when returning lazy structures. See, e.g. http://debasishg.blogspot.com/2009/01/to-tail-recurse-or-not-part-2-follow-up.html

[identity profile] nivanych.livejournal.com 2010-01-30 12:20 pm (UTC)(link)
> is there something that does it already

А какая разница, если это пишется за полминуты?

[identity profile] nivanych.livejournal.com 2010-01-30 02:06 pm (UTC)(link)
Вот так будет лучше (и паттерн полный) ->
pairwise (x:y:rest) = (x,y) : pairwise rest
pairwise _ = []

[identity profile] vyahhi.livejournal.com 2010-01-30 02:46 pm (UTC)(link)
zip xs (tail xs)
и как-нибудь взять все элементы с позиций 0,2..

[identity profile] nivanych.livejournal.com 2010-01-30 02:53 pm (UTC)(link)
Так и быть ;-)

takeNth _ [] = []
takeNth n lst = (head lst) : takeNth (drop n lst)

pairwise lst = takeNth 1 $ zip lst (tail lst)

[identity profile] nivanych.livejournal.com 2010-01-30 02:54 pm (UTC)(link)
Описался. Конечно же,
pairwise lst = takeNth 2 $ zip lst (tail lst)

[identity profile] vyahhi.livejournal.com 2010-01-30 03:34 pm (UTC)(link)
Да, даже длиннее получилось :(

[identity profile] nivanych.livejournal.com 2010-01-30 03:36 pm (UTC)(link)
Зато более универсально.
Это самое takeNth может ещё где-то потребоваться.

[identity profile] nivanych.livejournal.com 2010-01-30 06:27 pm (UTC)(link)
Там вон снизу прикольную идею с cycle высказали.
На той же идее
takeNth n lst = map fst $ filter (\(x,t)-> t == 1) $ zip lst $ cycle [1..n]
Но по-моему, это уже извраты,
которые непонятно, для чего нужны,
кроме как, сэкономить лишнюю строчку.
Лучше писать тупо и понятно,
потом свой же код проще смотреть.

полет фантазии

[identity profile] huzhepidarasa.livejournal.com 2010-01-30 04:15 pm (UTC)(link)
pairwise xs = uncurry zip $ pairmap (map snd) $ partition fst $ zip (cycle [True, False]) xs
  where pairmap f (x,y) = (f x, f y)

хотел без рекурсии и не определяя никаких вспомогательных ф-й, но не вышло

Re: полет фантазии

[identity profile] huzhepidarasa.livejournal.com 2010-01-30 04:21 pm (UTC)(link)
объединяя с предыдущей идеей

pairwise xs = map snd $ filter fst $ zip (cycle [True, False]) $ zip xs (tail xs)

Re: полет фантазии

[identity profile] ivan-gandhi.livejournal.com 2010-01-30 06:06 pm (UTC)(link)
О! cycle приходит на помощь!

Re: полет фантазии

[identity profile] nivanych.livejournal.com 2010-01-30 06:17 pm (UTC)(link)
Прикольная идея ;-)

[identity profile] http://users.livejournal.com/_adept_/ 2010-01-31 10:33 pm (UTC)(link)
Как всегда, забыли unfoldr :)


splitInto n = unfoldr (chunk n)
where chunk _ [] = Nothing
chunk n lst = Just $ splitAt n lst

[identity profile] ivan-gandhi.livejournal.com 2010-02-01 12:12 am (UTC)(link)
Вот! Не слыхал про unfold раньше, но это то, что должно было вертеться на языке.