Sự tương đương eta cho các chức năng có tương thích với hoạt động seq của Haskell không?


14

Bổ đề: Giả sử tương đương eta chúng ta có điều đó (\x -> ⊥) = ⊥ :: A -> B.

Bằng chứng: ⊥ = (\x -> ⊥ x)bằng cách tương đương eta, và (\x -> ⊥ x) = (\x -> ⊥)bằng cách giảm theo lambda.

Báo cáo Haskell 2010, phần 6.2 chỉ định seqhàm theo hai phương trình:

seq :: a -> b -> b
seq ⊥ b = ⊥
seq ab = b, nếu a

Sau đó, nó tuyên bố "Do đó, không giống với \ x ->, vì seq có thể được sử dụng để phân biệt chúng."

Câu hỏi của tôi là, đó thực sự là một hệ quả của định nghĩa seq?

Đối số ngầm dường như seqsẽ không thể tính được nếu seq (\x -> ⊥) b = ⊥. Tuy nhiên tôi đã không thể chứng minh rằng điều đó seqsẽ không thể tính toán được. Dường như với tôi như vậy seqvừa đơn điệu, vừa liên tục, điều đó đặt nó vào cõi tính toán.

Một thuật toán triển khai như seq có thể hoạt động bằng cách cố gắng tìm kiếm một số xnơi f x ≠ ⊥bằng cách liệt kê miền fbắt đầu bằng. Mặc dù việc thực hiện như vậy, thậm chí nếu có thể, sẽ có nhiều lông một khi chúng ta muốn tạo seqđa hình.

Có bằng chứng cho thấy không có sự tính toán seqdanh sách chỉ rõ (\x -> ⊥)với ⊥ :: A -> B? Ngoài ra, có một số xây dựng seqmà không xác định (\x -> ⊥)với ⊥ :: A -> B?

Câu trả lời:


6

Trước tiên, chúng ta hãy rõ ràng về cách seqphân biệt với λ x . :λx.

bottom :: a
bottom = bottom

eta :: a -> b
eta x = bottom

-- This terminates
fortytwo = seq eta 42

-- This does not terminate
infinity = seq bottom 42

Do đó, nó là một thực tế thực nghiệm rằng trong Haskell λ x . Được phân biệt hoạt động. Nó cũng là một thực tế, và một điều khá rõ ràng, đó là tính toán được vì Haskell tính toán nó. Rất nhiều về Haskell. Bạn đang hỏi về các giai đoạn rất đặc biệt của tài liệu Haskell. Tôi đọc nó như nói rằng nó được cho là thỏa mãn hai phương trình đã cho, nhưng hai phương trình đó không đủ cho định nghĩa của . Đây là lý do tại sao: Tôi có thể cung cấp cho bạn hai mô hình của (chỉ cần gõ) λ -calculus trong đó là tính toán và thỏa mãn các phương trình nhất định, nhưng thuộc một trong các mô hình λ x . λx.seqseqseqλseqλx. đồng ý, trong khi khác thì không.

Trong một mô hình lý thuyết miền đơn giản trong đó -expression được diễn giải trong miền của các hàm liên tục [ D E ], chúng ta có = λ x . , rõ ràng. Lấy tên miền Scott hiệu quả hoặc một số như vậy để làm cho mọi thứ có thể tính toán được. Thật dễ dàng để xác định trong một mô hình như vậy.λ[DE]= =λx.seq

Chúng tôi cũng có thể có một mô hình -calculus trong đó này khác biệt λ x . , và sau đó dĩ nhiên η -rule không thể giữ. Ví dụ, chúng ta có thể làm điều này bằng việc giải thích các chức năng trong lĩnh vực [ D E ] , ví dụ, tên miền không gian chức năng với một đáy thêm đính kèm. Bây giờ là, tốt, dưới cùng của [ D E ] , trong khi λ x . là yếu tố chỉ ở trên nó. Chúng không thể được phân biệt bằng ứng dụng vì cả hai đều đánh giáλseqλx.η[DE][DE]λx. , không có vấn đề gì bạn áp dụng chúng vào (họextensionally bình đẳng). Nhưng chúng tôi cómột bản đồ giữa các miền và nó phân biệt đáy với tất cả các yếu tố khác.seq


1
Đó là một thực tế thực nghiệm rằng trong GHC và / hoặc Hugs và λx.⊥. May mắn thay, Haskell không được xác định bởi một triển khai. Câu hỏi của tôi cho thấy Haskell chưa được xác định rõ ràng liên quan đến seq.
Russell O'Connor

Bạn có thể đưa ra một tham chiếu đến những gì bạn có nghĩa là "miền Scott hiệu quả" Có lẽ điều đó không ngụ ý rằng thứ tự từng phần là có thể quyết định. Ngoài ra, STLC không phải là đa hình, nhưng Haskell thì có. Thông thường Haskell được hiểu trong Hệ thống F hoặc một trong các dẫn xuất của nó. Điều này ảnh hưởng đến cuộc tranh luận của bạn như thế nào?
Russell O'Connor

Mục 1.1.4 của bằng tiến sĩ của tôi luận án andrej.com/thesis/thesis.pdf có một định nghĩa ngắn về các tên miền Scott hiệu quả và đây thực sự là bản hit đầu tiên của Google được cung cấp miễn phí.
Andrej Bauer

2
Nếu bạn viết bằng chứng cho tôi, bạn sẽ nhận được việc triển khai Haskell 98 trong đó quy tắc eta giữ cho phép (Foldr (\ ab -> fab) z xs) được tối ưu hóa thành (Foldr fz xs) làm tăng hiệu suất tiệm cận từ O (n ^ 2) đến O (n) (xem ghc.haskell.org/trac/ghc/ticket/7436 ). Hấp dẫn hơn, nó sẽ cho phép NewTypeWrapper trong (NewTypeWrapper. F) được tối ưu hóa mà không buộc f phải mở rộng eta và ngăn chặn một số hình phạt hiệu suất tiệm cận hiện hành do newTypes áp dụng trong GHC (ví dụ như sử dụng Foldr).
Russell O'Connor

1
Trên thực tế, bạn sẽ phải đảm bảo rằng trình biên dịch của bạn luôn thực hiện như . Đó là, bạn có thể bị cám dỗ không phải lúc nào cũng ký hợp đồng và theo nguyên tắc λ x . sẽ là "đôi khi có thể phân biệt", một tình huống rất nguy hiểm. Để chắc chắn rằng đây không phải là trường hợp, bạn cần thực hiện một cách thông minh bao gồm sinh ra vô số quá trình mỗi quy trình áp dụng chức năng của bạn cho một yếu tố cơ bản. Nếu bất kỳ quá trình kết thúc, sau đó có thể tiến hành. Sẽ rất thú vị để xem nếu chúng ta có thể làm điều này một cách tuần tự. Hừm. λx.λx.seqseq
Andrej Bauer

2

Lưu ý rằng đặc điểm kỹ thuật seqmà bạn trích dẫn không phải là định nghĩa của nó. Để trích dẫn báo cáo Haskell "Hàm seq được xác định bởi các phương trình : [và sau đó là phương trình bạn đưa ra]".

Đối số được đề xuất dường như là seq sẽ không thể tính được nếu seq (\ x -> ⊥) b =.

Hành vi như vậy sẽ vi phạm các đặc điểm kỹ thuật của seq.

Điều quan trọng, vì seqlà đa hình, seqkhông thể được định nghĩa theo thuật ngữ giải cấu trúc (phép chiếu / khớp mẫu, v.v.) trên một trong hai tham số.

Có bằng chứng nào cho thấy không có seq có thể tính toán nào xác định (\ x ->) với ⊥ :: A -> B không?

Nếu seq' (\x -> ⊥) b, người ta có thể nghĩ rằng chúng ta có thể áp dụng tham số đầu tiên (là hàm) cho một số giá trị và sau đó lấy ra. Nhưng, seqkhông bao giờ có thể xác định tham số đầu tiên có giá trị hàm (ngay cả khi nó là một tham số cho một số sử dụng seq) vì loại đa hình tham số của nó. Tham số có nghĩa là chúng ta không biết gì về các tham số. Hơn nữa, seqkhông bao giờ có thể có một biểu thức và quyết định "đây có phải là ⊥?" (xem vấn đề Dừng), seqchỉ có thể cố gắng đánh giá nó và tự phân kỳ thành.

Có gì seqlàm là để đánh giá các tham số đầu tiên (không hoàn toàn, nhưng để "hình thức đầu yếu bình thường" [1], tức là đến-top nhất constructor), sau đó trở về tham số thứ hai. Nếu tham số đầu tiên xảy ra là (nghĩa là một tính toán không kết thúc) thì việc đánh giá nó gây ra seqkhông kết thúc, và do đó seq ⊥ a = ⊥.

[1] Các định lý miễn phí trong sự hiện diện của seq - Johann, Voigtlander http://www.iai.uni-bonn.de/~jv/p76-voigtlaender.pdf


Thông số kỹ thuật tôi đưa ra cho seq là định nghĩa của seq vì đó chính xác là những gì báo cáo Haskell 2010 nói trong Phần 6.2. Định nghĩa hoạt động của bạn về seq không được báo cáo Haskell 2010 hỗ trợ: các từ "dạng bình thường" chỉ xuất hiện một lần trong báo cáo trong một bối cảnh hoàn toàn khác. Điều này cũng không phù hợp với sự hiểu biết của tôi rằng GHC sẽ thường giảm đối số thứ hai xuống seq trước đối số thứ nhất hoặc đối số thứ nhất sẽ không bị giảm đi vì bộ phân tích nghiêm ngặt đã chứng minh rằng nó không phải là đáy.
Russell O'Connor

Tham số không trực tiếp nói rằng chúng ta không thể áp dụng bất kỳ trình giải mã nào, cũng như không nói rằng chúng ta không bao giờ có thể xác định tham số đầu tiên bằng một giá trị hàm. Tất cả các tham số nói cho phép tính lambda đa hình với các điểm cố định là seq có thể hấp thụ các hàm nghiêm ngặt, hay nói chung là các mối quan hệ chặt chẽ nhất định đối với các thuật ngữ có chứa seq. Tôi thừa nhận rằng có thể sử dụng tham số để chứng minh (\ x ->) & ne; , Nhưng tôi muốn thấy một bằng chứng nghiêm ngặt.
Russell O'Connor

Trong trường hợp của một hàm f : forall a . a -> T(trong đó Tcó một số loại khác), thì fkhông thể áp dụng bất kỳ bộ giải mã nào cho đối số đầu tiên của nó vì nó không biết nên sử dụng bộ giải mã nào. Chúng tôi không thể làm một "trường hợp" về các loại. Tôi đã cố gắng cải thiện câu trả lời trên (bao gồm cả trích dẫn thông tin về seqviệc đánh giá để trở thành dạng bình thường).
dorchard

Tôi có thể cố gắng thực hiện bằng chứng nghiêm ngặt sau này nếu tôi tìm thấy thời gian (sử dụng các mối quan hệ theo phong cách của Reynold có thể là một cách tiếp cận tốt).
dorchard

@ RussellO'Connor: mô tả của seq không "không phù hợp" với các hành vi đó, nó chỉ là một đặc điểm kỹ thuật hoạt động (và hành vi là tối ưu hóa không thay đổi kết quả cuối cùng).
Blaisorblade

2

λx.λx.

Samson Abramsky đã xem xét vấn đề này từ lâu và đã viết một bài báo có tên " The Lazy Lambda Compus ". Vì vậy, nếu bạn muốn định nghĩa chính thức, đây là nơi bạn có thể nhìn.


1
Rõ ràng, những chi tiết này chỉ được xác định bằng cách bỏ vào "nhân Haskell". Nó được định nghĩa ở đâu? Báo cáo cho biết, trong Sec. 1.2 : "Mặc dù hạt nhân không được chỉ định chính thức, nhưng về cơ bản, nó là một biến thể hơi có đường của phép tính lambda với ngữ nghĩa biểu thị đơn giản. Việc dịch từng cấu trúc cú pháp vào hạt nhân được đưa ra khi cú pháp được đưa ra."
Blaisorblade

Báo cáo Haskell 2010 cũng nói như vậy , thật đáng kinh ngạc.
Blaisorblade

Cảm ơn bạn đã tham khảo Abramsky! Tôi đọc lướt nó để xem nó trả lời câu hỏi như thế nào và tôi đã đưa ra câu trả lời sau: cstheory.stackexchange.com/a/21732/989
Blaisorblade

2

Chứng minh rằng λ x. Ω ‌ Ω in là một trong những mục tiêu mà Abramsky đặt ra cho lý thuyết tính toán lambda lười biếng của mình (trang 2 của bài báo , đã được trích dẫn bởi Uday Reddy), bởi vì cả hai đều ở dạng yếu đầu bình thường. Theo định nghĩa 2.7, ông thảo luận một cách rõ ràng rằng giảm eta λ x. M x → M thường không hợp lệ, nhưng có thể nếu M chấm dứt trong mọi môi trường. Điều này không có nghĩa là M phải là một hàm tổng - chỉ đánh giá M phải chấm dứt (ví dụ bằng cách giảm xuống lambda).

Câu hỏi của bạn dường như được thúc đẩy bởi mối quan tâm thực tế (hiệu suất). Tuy nhiên, mặc dù Báo cáo Haskell có thể chưa hoàn toàn rõ ràng, tôi nghi ngờ rằng việc đánh đồng x. ⊥ với sẽ tạo ra một triển khai hữu ích của Haskell; cho dù nó có thực hiện Haskell '98 hay không thì vẫn còn gây tranh cãi, nhưng được đưa ra nhận xét, rõ ràng các tác giả dự định nó sẽ là trường hợp.

Cuối cùng, làm thế nào seq để tạo các phần tử cho một kiểu đầu vào tùy ý? (Tôi biết QuickCheck định nghĩa kiểu chữ tùy ý cho điều đó, nhưng bạn không được phép thêm các ràng buộc như vậy ở đây). Điều này vi phạm tham số.

Đã cập nhật : Tôi đã không quản lý để mã quyền này (vì tôi không rành về Haskel) và việc sửa lỗi này dường như yêu cầu các runSTvùng lồng nhau . Tôi đã thử sử dụng một ô tham chiếu duy nhất (trong đơn vị ST) để lưu các phần tử tùy ý như vậy, đọc chúng sau và làm cho chúng có sẵn trên toàn cầu. Tham số chứng minh rằng break_parametricitybên dưới không thể được xác định (ngoại trừ bằng cách trả về đáy, ví dụ như lỗi), trong khi nó có thể khôi phục các phần tử mà seq đề xuất của bạn sẽ tạo ra.

import Control.Monad.ST
import Data.STRef
import Data.Maybe

produce_maybe_a :: Maybe a
produce_maybe_a = runST $ do { cell <- newSTRef Nothing; (\x -> writeSTRef cell (Just x) >> return x) `seq` (readSTRef cell) }

break_parametricity :: a
break_parametricity = fromJust produce_maybe_a

Tôi phải thừa nhận rằng tôi hơi mờ nhạt trong việc chính thức hóa bằng chứng tham số cần thiết ở đây, nhưng việc sử dụng tham số không chính thức này là tiêu chuẩn trong Haskell; nhưng tôi đã học được từ các tác phẩm của Derek Drey rằng lý thuyết cần thiết đang nhanh chóng được thực hiện trong những năm cuối cùng này.

EDIT:

  • Tôi thậm chí không chắc liệu bạn có cần các phần mở rộng đó, được nghiên cứu cho các ngôn ngữ giống như ML, mệnh lệnh và chưa được kiểm tra hay không, hoặc liệu các lý thuyết cổ điển về tham số bao trùm Haskell.
  • Ngoài ra, tôi đã đề cập đến Derek Dreyer đơn giản vì sau này tôi chỉ tình cờ thấy tác phẩm của Uday Reddy - tôi mới biết về nó gần đây từ "Bản chất của Reynold". (Tôi chỉ bắt đầu thực sự đọc tài liệu về tham số trong tháng trước hoặc lâu hơn).

Đánh giá (\x -> writeSTRef cell (Just x) >> return x)trên các đầu vào ngẫu nhiên không thực hiện ghi vào ô. Chỉ các lệnh ST làm cho nó thành chuỗi được truyền vào runSTđược thực hiện. Tương tự, chạy main = (putStrLn "Hello") `seq` (return ())không in bất cứ điều gì lên màn hình.
Russell O'Connor

@ RussellO'Connor, tất nhiên là bạn đúng - kiểm tra rất khó vì seq không có hành vi mà chúng ta thảo luận. Nhưng tôi vẫn nghĩ rằng việc tạo ra các phần tử phá vỡ tham số mỗi se. Tôi sẽ cố gắng sửa câu trả lời để minh họa điều đó.
Blaisorblade

Hừm, cách khắc phục rõ ràng cho câu trả lời yêu cầu các vùng runST lồng nhau và sử dụng ô từ vùng bên ngoài ở vùng bên trong, nhưng điều đó không được phép.
Blaisorblade
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.