2010-01-28 30 views

Trả lời

33

Những lựa chọn thay thế cho mono cho I/O bằng ngôn ngữ chức năng thuần túy?

Tôi biết hai lựa chọn thay thế trong các tài liệu:

  • Một là một cái gọi là tuyến tính loại hệ thống. Ý tưởng là giá trị của loại tuyến tính phải được sử dụng chính xác một lần: bạn không thể bỏ qua nó và bạn không thể sử dụng nó hai lần. Với ý tưởng này, bạn cung cấp cho trạng thái của thế giới một loại trừu tượng (ví dụ: World) và bạn làm cho nó tuyến tính. Nếu tôi đánh dấu loại tuyến tính bằng dấu sao, thì dưới đây là các loại hoạt động I/O:

    getChar :: World* -> (Char, World*) 
    putChar :: Char -> World* -> World* 
    

    v.v. Trình biên dịch sắp xếp để đảm bảo bạn không bao giờ sao chép thế giới, và sau đó nó có thể sắp xếp để biên dịch mã cập nhật thế giới tại chỗ, an toàn vì chỉ có một bản sao.

    Cách nhập duy nhất bằng ngôn ngữ Clean dựa trên tuyến tính.

    Hệ thống này có một số lợi thế; đặc biệt, nó không thực thi tổng số thứ tự trên các sự kiện mà monads làm. Nó cũng có xu hướng tránh "bin" IO "bạn thấy trong Haskell nơi tất cả tính toán hiệu quả được ném vào đơn IO và tất cả chúng đều được đặt hàng hoàn toàn cho dù bạn muốn tổng số đơn đặt hàng hay không.

  • Hệ thống khác Tôi nhận thức được xảy ra trước monads và sạch và được dựa trên ý tưởng rằng một chương trình tương tác là một chức năng từ một (có thể là vô hạn) chuỗi các yêu cầu đến một (có thể là vô hạn) chuỗi các phản hồi. Hệ thống này, được gọi là "hộp thoại", là địa ngục thuần túy để lập trình. Không ai nhớ nó, và nó không có gì đặc biệt để giới thiệu nó. Lỗi của nó được liệt kê độc đáo trong the paper that introduced monadic I/O (Imperative Functional Programming) bởi Wadler và Peyton Jones. Bài viết này cũng đề cập đến một hệ thống I/O dựa trên sự tiếp tục được giới thiệu bởi nhóm Yale Haskell nhưng nó đã tồn tại trong thời gian ngắn.

+1

Trình tự thông qua ràng buộc đơn nguyên là khá nhiều chỉ là kiểu được kiểm tra kiểu liên tục được kiểm tra kiểu, phải không? Ấn tượng của tôi là các monads và continuations hầu như có thể hoán đổi cho nhau, ngoại trừ việc các sự tiếp tục được quyết định không, nói chung, hoặc là ấm áp * hoặc * mờ. –

+2

Continuations hình thành một đơn nguyên nhưng monads là decidedly * not * continuations. CPS là cách mạnh mẽ hơn bởi vì bạn được phép tạo bản sao của sự vật (bao gồm cả việc tiếp tục!). Monads hạn chế mọi thứ nghiêm trọng hơn nhiều so với việc kiểm tra kiểu đơn thuần. –

+0

"Monads được quyết định không tiếp tục" - không, nhưng mối quan hệ không chỉ là một bản InstanceOf. Cf. http://lambda-the-ultimate.org/node/3235 Các lý thuyết và Monads, Hyland & Power, 2007. –

4

gõ độc đáo được sử dụng trong Clean

5

Nếu bằng cách "tinh khiết" bạn có nghĩa là "referentially minh bạch", có nghĩa là, rằng một chức năng áp dụng là tự do hoán đổi cho nhau với kết quả đánh giá của nó (và do đó mà gọi một hàm với cùng các đối số có cùng kết quả mỗi lần), bất kỳ khái niệm nào về trạng thái IO bị loại trừ khá nhiều theo định nghĩa.

Có hai chiến lược thô mà tôi biết:

  • Hãy một chức năng làm IO, nhưng chắc chắn rằng nó không bao giờ có thể được gọi hai lần với những lập luận chính xác cùng; vấn đề phụ này bằng cách cho phép các chức năng trở nên nhỏ gọn "tham chiếu trong suốt".

  • Điều trị toàn bộ chương trình dưới dạng một hàm thuần túy lấy "tất cả đầu vào nhận được" làm đối số và trả về "tất cả đầu ra được tạo", với cả hai biểu diễn dưới dạng luồng lười để cho phép tương tác.

Có nhiều cách để thực hiện cả hai cách tiếp cận, cũng như một số mức chồng chéo - ví dụ, trong trường hợp thứ hai, các chức năng hoạt động trên luồng I/O không được gọi hai lần cùng một phần của luồng. Cách nhìn vào nó có ý nghĩa hơn phụ thuộc vào loại hỗ trợ mà ngôn ngữ mang lại cho bạn.

Trong Haskell, IO là một loại đơn nguyên tự động chủ đề tuần tự thông qua mã (tương tự như hàm tinh khiết State monad), như vậy, về mặt khái niệm, mỗi cuộc gọi đến hàm khác không tinh khiết đều có giá trị khác nhau của ngầm "trạng thái của thế giới bên ngoài".

Cách tiếp cận phổ biến khác mà tôi biết là sử dụng một cái gì đó như linear types cho một kết thúc tương tự; đảm bảo rằng các hàm không tinh khiết không bao giờ nhận được cùng một đối số hai lần bằng cách có các giá trị không thể sao chép hoặc sao chép, do đó các giá trị cũ của "trạng thái của thế giới bên ngoài" không thể được giữ lại và sử dụng lại.

5

Imperative Functional Programming bởi Peyton Jones và Wadler là phải đọc nếu bạn quan tâm đến chức năng IO. Các phương pháp khác mà họ thảo luận là:

  • Dialogues đó là suối lười biếng của phản ứng và yêu cầu

type Dialogue = [Response] -> [Request]

main :: Dialogue

  • continuations - mỗi hoạt động IO mất sự tiếp nối làm đối số

  • Kiểu tuyến tính - loại hệ thống hạn chế bạn theo cách mà bạn không thể sao chép hoặc phá hủy trạng thái bên ngoài, điều đó có nghĩa là bạn không thể gọi hàm hai lần với cùng trạng thái.

3

Functional Reactive Programming là một cách khác để xử lý việc này.

+1

Tôi chưa từng nghe thuật ngữ "Lập trình phản ứng chức năng". Bạn có thể thay đổi nó thành "Lập trình phản ứng chức năng" không? Câu trả lời tuyệt vời khác. –

+0

Không sao, cảm ơn vì đã chú ý. Không có ý tưởng làm thế nào tôi sai chính tả đó. –

Các vấn đề liên quan