Переліки відмінностей у функціональному програмуванні


14

Питання Що нового в чисто функціональних структурах даних після Окасакі? , і епічна відповідь jbapple, згадана з використанням списків різниць у функціональному програмуванні (на відміну від логічного програмування), що мене нещодавно цікавило. Це змусило мене знайти реалізацію списку різниць для Haskell. У мене є два запитання (пробачте / виправте мене, якщо я повинен зробити їм два різні запитання на StackExchange).

Просте запитання полягає в тому, чи хтось знає про академічне врахування різницьких списків у функціональному програмуванні та / або реалізаціях, окрім списку в бібліотеці Haskell? Відповідь jbapple не дала цитування для різницьких списків (різницькі списки в логічному програмуванні існують у кращому і в декількох джерелах, які я маю Around Here Somewhere (TM)). Перш ніж знайти реалізацію Haskell, я не знав, що ідея перейшла від логіки до функціонального програмування. Звичайно, списки різниці Haskell є чимось природним використанням функцій вищого порядку і працюють зовсім інакше, ніж в логічному програмуванні, але інтерфейс, безумовно, схожий.

Більш цікава (і куди більш нечітка) річ, про яку я хотів запитати, - чи здається, що заявлена ​​асимптотична верхня межа для вищезгаданої бібліотеки списку різниць Хаскеля видається правильною / правдоподібною. Моя плутанина може бути через те, що я пропускаю щось із очевидним щодо аргументації складності з лінню, але заявлені межі мають сенс для мене, лише якщо заміна на велику структуру даних (або формування закриття, або змінний пошук, або щось таке ) завжди потребує постійного часу. Або "улов" просто у тому, що немає часу для "голови" та "хвоста", не пов'язаного саме з тим, що ці операції, можливо, доведеться орати через довільну купу відкладених обчислень / підстановок?


1
Спочатку мене бентежили "функціональні мови програмування (на відміну від функціональних мов програмування)", але ти мав на увазі написати "(на відміну від мов логічного програмування)"?
— Tsuyoshi Ito

Ой, ой, так, це я мав на увазі, це зараз виправлено.
— Роб Сіммонс

Друге питання здається мені більш підходящим щодо Stack Overflow, але тепер, коли ви його тут задали, може бути краще почекати, щоб дізнатись, чи хтось може відповісти тут. Особисто я не можу знайти жодних причин сумніватися у заявлених межах прочитання вихідного коду, але я не дотримувався ваших міркувань, щоб сумніватися в них, а також я можу щось пропустити.
— Tsuyoshi Ito

Відповіді:


9

Або "улов" просто у тому, що немає часу для "голови" та "хвоста", не пов'язаного саме з тим, що ці операції, можливо, доведеться орати через довільну купу відкладених обчислень / підстановок?

Θ(m)m

O(1) fromList

{-# LANGUAGE NoMonomorphismRestriction #-}

data DL a = Id
          | Cons a
          | Compose (DL a) (DL a)

fromList [] = Id
fromList (x:xs) = Compose (Cons x) (fromList xs)

toList x = help x []
    where help Id r = r
          help (Cons a) r = a:r
          help (Compose f g) r = help f $ help g r

empty = Id

singleton = Cons

cons x = append (singleton x)

append = Compose

snoc xs x = append xs (singleton x)

Θ(n)headtail[a] -> [a]toList


Тож те, що ти отримуєш від лінощів, - це лише те, що запит на хвіст списку двічі не зробить дорогу операцію двічі, що приємно.
— Роб Сіммонс

@Rob, я не розумію, що ти маєш на увазі під цим.
— jbapple

Я думаю, що пункт, який я намагався зробити (погано), проілюстрований на цьому прикладі: у мене надзвичайно довгий перелік різниць "xs", який я робив, повторюючи "заношування" речей до оригінального списку. Перший раз, коли я називаю "head xs", я сподіваюся, що знадобиться O (n) час, щоб зробити відкладені обчислення; однак, оскільки це обчислення має бути запам'ятоване, другий виклик "head xs" (для тих же "xs") повинен зайняти O (1) час.
— Роб Сіммонс

1
Ну, я з цим згоден, але лінь, на яку я посилався у своїй відповіді, стосувалась списку, який не використовується в snoc або head. Отож, педантичний, як це є, мене збентежило "що" у вашому висловленні, "що ви отримуєте від лінощів". Я б сказав, що ваш приклад і моє - це дві речі, які ви отримуєте від ліні.
— jbapple

Гаразд - і це уточнення допомагає мені краще зрозуміти і ваш попередній пункт.
— Роб Сіммонс

12

Так, межі залежать від припущення, що склад функції займає постійний час. В основному, якщо у вас є список приєднання:

datatype 'a join = Nil | Cons of 'a * 'a join | Join of 'a join * 'a join

O(n)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.