Danh sách khác biệt trong lập trình chức năng


13

Câu hỏi Có gì mới trong cấu trúc dữ liệu chức năng thuần túy kể từ Okasaki? và câu trả lời sử thi của jbapple, được đề cập bằng cách sử dụng danh sách khác biệt trong lập trình chức năng (trái ngược với lập trình logic), đó là điều mà gần đây tôi đã quan tâm. Điều này dẫn tôi đến việc thực hiện danh sách khác biệt cho Haskell. Tôi có hai câu hỏi (tha thứ / sửa lỗi cho tôi nếu tôi nên đặt chúng thành hai câu hỏi khác nhau trên StackExchange).

Câu hỏi đơn giản là, có ai biết về việc xem xét học thuật các danh sách khác biệt trong lập trình chức năng và / hoặc triển khai bên cạnh một trong thư viện Haskell không? Câu trả lời của jbapple đã không đưa ra một trích dẫn cho các danh sách khác biệt (danh sách khác biệt trong lập trình logic tồn tại trong truyền thuyết và trong một vài nguồn mà tôi có quanh đây ở đâu đó (TM)). Trước khi tìm thấy triển khai Haskell, tôi không biết rằng ý tưởng đã chuyển từ logic sang lập trình chức năng. Cấp, các danh sách khác biệt Haskell là một cái gì đó sử dụng tự nhiên các hàm bậc cao hơn và hoạt động hoàn toàn khác với các hàm trong lập trình logic, nhưng giao diện chắc chắn tương tự nhau.

Điều thú vị hơn (và xa đầu hơn) mà tôi muốn hỏi là liệu giới hạn trên không có triệu chứng được tuyên bố đối với thư viện danh sách khác biệt Haskell đã nói ở trên có vẻ đúng / hợp lý hay không. Sự nhầm lẫn của tôi có thể là do tôi thiếu một cái gì đó rõ ràng về lý do phức tạp với sự lười biếng, nhưng các giới hạn được tuyên bố chỉ có ý nghĩa với tôi nếu việc thay thế một cấu trúc dữ liệu lớn (hoặc hình thành đóng cửa, hoặc tra cứu biến đổi, hoặc một cái gì đó ) luôn luôn mất thời gian. Hay là "bắt" chỉ đơn giản là không bị ràng buộc về thời gian chạy cho "đầu" và "đuôi" chính xác bởi vì các hoạt động đó có thể phải cày xới qua một đống tính toán / thay thế bị trì hoãn?


1
Lúc đầu, tôi đã bị nhầm lẫn bởi các ngôn ngữ lập trình chức năng (trái ngược với các ngôn ngữ lập trình chức năng), nhưng bạn có ý định viết ra (trái ngược với các ngôn ngữ lập trình logic) không?
Tsuyoshi Ito

Ôi trời - vâng, đó là điều tôi muốn nói, giờ nó đã được sửa.
Rob Simmons

Câu hỏi thứ hai có vẻ phù hợp hơn với Stack Overflow đối với tôi nhưng, bây giờ bạn đã hỏi nó ở đây, có lẽ tốt hơn để chờ xem liệu ai đó có thể trả lời ở đây không. Cá nhân tôi không thể tìm thấy bất kỳ lý do nào để nghi ngờ giới hạn được yêu cầu khi đọc mã nguồn, nhưng tôi đã không tuân theo lý do của bạn để nghi ngờ họ, và tôi cũng có thể đang thiếu một cái gì đó.
Tsuyoshi Ito

Câu trả lời:


8

Hay là "bắt" chỉ đơn giản là không bị ràng buộc về thời gian chạy cho "đầu" và "đuôi" chính xác bởi vì các hoạt động đó có thể phải cày xới qua một đống tính toán / thay thế bị trì hoãn?

Tôi nghĩ điều đó ít nhiều đúng. Tuy nhiên, các DL chỉ thực sự có các hoạt động xây dựng nhanh, do đó, cày là , trong đó m là số lượng các hoạt động được sử dụng để xây dựng DL.Θ(m)m

Phiên bản phân cấp sau đây của một số thao tác thiết yếu đòi hỏi sự lười biếng đối với , nhưng nếu không thì nên là một cách hiểu đơn giản về giới hạn phức tạp được yêu cầu trong bản gốc .Ôi(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


Vì vậy, những gì bạn nhận được từ sự lười biếng chỉ là việc yêu cầu phần đuôi của danh sách hai lần sẽ không thực hiện thao tác đắt tiền hai lần, điều này thật tuyệt.
Rob Simmons

@Rob, tôi không hiểu ý của bạn là gì.
jbapple

Tôi nghĩ rằng điểm mà tôi đang cố gắng đưa ra (rất tệ) được minh họa bằng ví dụ này: Tôi có một danh sách khác biệt cực kỳ dài "xs" mà tôi đã tạo ra bằng cách liên tục "đánh hơi" những thứ trong danh sách ban đầu. Lần đầu tiên tôi gọi "head xs", tôi hy vọng rằng sẽ mất O (n) thời gian để thực hiện tính toán hoãn lại; tuy nhiên, vì tính toán đó sẽ được ghi nhớ, nên cuộc gọi thứ hai đến "head xs" (với cùng "xs") sẽ mất thời gian O (1).
Rob Simmons

1
Chà, tôi đồng ý với điều đó, nhưng sự lười biếng mà tôi đã tham khảo trong câu trả lời của mình là về từ ListList, không được sử dụng trong snoc hoặc head. Vì vậy, như là, mang tính mô phạm, tôi đã bị nhầm lẫn bởi "cái gì" trong câu nói của bạn "những gì bạn nhận được từ sự lười biếng". Tôi muốn nói ví dụ của bạn và của tôi là hai điều bạn nhận được từ sự lười biếng.
jbapple

Ok - và làm rõ điều đó cũng giúp tôi hiểu rõ hơn về điểm trước đó của bạn.
Rob Simmons

11

Có, giới hạn phụ thuộc vào giả định rằng thành phần chức năng mất thời gian không đổi. Về cơ bản, nếu bạn có một danh sách tham gia:

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

Ôi(n)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.