2010-06-08 35 views
38

Về cơ bản, tôi biết cách tạo cấu trúc dữ liệu đồ thị và sử dụng thuật toán Dijkstra trong các ngôn ngữ lập trình, nơi cho phép các hiệu ứng phụ. Thông thường, thuật toán đồ thị sử dụng cấu trúc để đánh dấu các nút nhất định là 'đã truy cập', nhưng điều này có tác dụng phụ, mà tôi đang cố tránh.Làm cách nào để triển khai biểu đồ và thuật toán đồ thị bằng ngôn ngữ lập trình chức năng?

Tôi có thể nghĩ một cách để thực hiện điều này bằng ngôn ngữ chức năng, nhưng về cơ bản yêu cầu phải vượt qua một lượng lớn trạng thái cho các chức năng khác nhau và tôi tự hỏi liệu có giải pháp tiết kiệm không gian hơn không.

Trả lời

15

Bạn có thể xem Haskell functional graph library của Martin Erwig hoạt động như thế nào. Ví dụ, shortest-path functions của nó đều thuần khiết và bạn có thể xem source code để biết cách triển khai.

Tùy chọn khác, like fmark mentioned, là sử dụng trừu tượng cho phép bạn thực hiện các chức năng thuần túy về trạng thái. Ông đề cập đến các đơn vị nhà nước (có sẵn trong cả hai giống lazystrict). Một tùy chọn khác, nếu bạn đang làm việc trong trình biên dịch/trình biên dịch GHC Haskell (hoặc, tôi nghĩ, bất kỳ triển khai Haskell nào hỗ trợ các loại hạng 2), một tùy chọn khác là the ST monad, cho phép bạn viết các hàm thuần túy xử lý các biến có thể thay đổi nội bộ .

+7

Tôi đã lấy các liên kết này từ trang thư viện đồ thị chức năng: Điều này giải thích lý thuyết: http://web.engr.oregonstate.edu/~erwig/papers/abstracts.html#JFP01 Tài liệu này lập chi tiết chương trình: http://web.engr.oregonstate.edu/~erwig/fgl/haskell/old/fgl0103.pdf Cùng với nhau, những giấy tờ này trả lời tốt nhất câu hỏi của tôi, đặc biệt là câu hỏi thứ hai, thực tế hơn một chút. Cảm ơn! – brad

-1

Hầu hết các ngôn ngữ chức năng đều hỗ trợ các chức năng bên trong. Vì vậy, bạn chỉ có thể tạo biểu diễn biểu đồ của bạn ở lớp ngoài cùng và chỉ tham chiếu nó từ hàm bên trong.

cuốn sách này đề cập đến một cách sâu đậm http://www.amazon.com/gp/product/0262510871/ref=pd_lpo_k2_dp_sr_1?ie=UTF8&cloe_id=aa7c71b1-f0f7-4fca-8003-525e801b8d46&attrMsgId=LPWidget-A1&pf_rd_p=486539851&pf_rd_s=lpo-top-stripe-1&pf_rd_t=201&pf_rd_i=0262011530&pf_rd_m=ATVPDKIKX0DER&pf_rd_r=114DJE8K5BG75B86E1QS

0

Tôi rất thích nghe về một số kỹ thuật thực sự thông minh, nhưng tôi nghĩ rằng có hai cách tiếp cận cơ bản:

  1. Sửa đổi một số đối tượng trạng thái toàn cầu. tức là các tác dụng phụ
  2. Chuyển biểu đồ dưới dạng đối số cho các hàm của bạn với giá trị trả về là biểu đồ sửa đổi. Tôi cho rằng đây là cách tiếp cận của bạn về "chuyển qua một số lượng lớn tiểu bang"

Đó là những gì được thực hiện trong lập trình hàm. Nếu trình biên dịch/thông dịch viên là tốt, nó sẽ giúp quản lý bộ nhớ cho bạn. Đặc biệt, bạn sẽ muốn chắc chắn rằng bạn sử dụng đệ quy đuôi, nếu bạn xảy ra để recurse trong bất kỳ chức năng của bạn.

3

Nếu bạn đang sử dụng haskell, ngôn ngữ chức năng duy nhất mà tôi quen thuộc, tôi khuyên bạn nên sử dụng State monad. Các đơn nguyên trạng thái là một trừu tượng cho một chức năng mà có một nhà nước và trả về một giá trị trung gian và một số giá trị nhà nước mới. Đây là considered idiomatic haskell cho những tình huống mà việc duy trì trạng thái lớn là cần thiết.

Đó là một thay thế đẹp hơn cho trạng thái trở về ngây thơ như là một kết quả hàm và chuyển nó thành một tham số "thành ngữ được nhấn mạnh trong hướng dẫn lập trình hàm mới bắt đầu. Tôi tưởng tượng hầu hết các ngôn ngữ lập trình hàm có cấu trúc tương tự.

+0

Nó sẽ là công bằng để mô tả một đơn nguyên nhà nước như xây dựng một hàm mảnh duy nhất của mảnh, và sau đó áp dụng các chức năng hoàn thành với nhà nước? – Greg

+0

@Greg: vâng. Monadizing một số thành ngữ lập trình (trong trường hợp này, đọc/viết trên toàn cầu nhà nước) là một cách để biến thành ngữ đó thành các mảnh composable. Bạn liên kết các mảnh với nhau để có được miếng lớn hơn. – dubiousjim

2

Tôi chỉ giữ bộ được truy cập làm nhóm và chuyển nó làm tham số. Có hiệu quả thời gian đăng nhập thực hiện của bộ của bất kỳ loại lệnh và bộ hiệu quả thêm các số nguyên.

Để đại diện cho biểu đồ, tôi sử dụng danh sách kề, hoặc tôi sẽ sử dụng bản đồ hữu hạn ánh xạ từng nút đến danh sách người kế thừa của nó. Nó phụ thuộc vào những gì tôi muốn làm.

Thay vì Abelson và Sussman, tôi khuyên bạn nên sử dụng số Purely Functional Data Structures của Chris Okasaki. Tôi đã liên kết với luận án của Chris, nhưng nếu bạn có tiền, anh ta mở rộng nó thành một excellent book.


Chỉ dành cho nụ cười, đây là một tìm kiếm theo chiều sâu đầu tiên tìm kiếm theo chiều ngược lại đáng sợ được thực hiện theo kiểu chuyển tiếp liên tục trong Haskell. Đây là ngay từ thư viện trình tối ưu hóa Hoopl:

postorder_dfs_from_except :: forall block e . (NonLocal block, LabelsPtr e) 
          => LabelMap (block C C) -> e -> LabelSet -> [block C C] 
postorder_dfs_from_except blocks b visited = 
vchildren (get_children b) (\acc _visited -> acc) [] visited 
where 
    vnode :: block C C -> ([block C C] -> LabelSet -> a) 
         -> ([block C C] -> LabelSet -> a) 
    vnode block cont acc visited = 
     if setMember id visited then 
      cont acc visited 
     else 
      let cont' acc visited = cont (block:acc) visited in 
      vchildren (get_children block) cont' acc (setInsert id  visited) 
     where id = entryLabel block 
    vchildren bs cont acc visited = next bs acc visited 
     where next children acc visited = 
       case children of []  -> cont acc visited 
           (b:bs) -> vnode b (next bs) acc  visited 
    get_children block = foldr add_id [] $ targetLabels bloc 
    add_id id rst = case lookupFact id blocks of 
         Just b -> b : rst 
         Nothing -> rst 
Các vấn đề liên quan