Tích cực nghiêm ngặt


10

Từ tài liệu tham khảo này: Tích cực nghiêm ngặt

Các điều kiện tích cực nghiêm ngặt loại trừ các tuyên bố như

data Bad : Set where
 bad : (Bad → Bad) → Bad
         A      B       C
 -- A is in a negative position, B and C are OK

Tại sao A là âm? Ngoài ra tại sao B được phép? Tôi hiểu tại sao C được phép.


1
Tôi không chắc tại sao điều này được gọi là "tiêu cực", nhưng nó thường được biết đến bởi lỗi mà nó tạo ra: lỗi tràn ngăn xếp :) Mã này có thể gây ra sự mở rộng vô hạn Avà làm nổ tung ngăn xếp (trong các ngôn ngữ dựa trên ngăn xếp).
wvxvw

phần đó tôi hiểu rằng bạn có thể viết những thứ tùy ý và do đó tính toán sẽ không kết thúc. cảm ơn
Pushpa

1
Tôi nghĩ rằng sẽ là một điều tốt khi đề cập đến việc không chấm dứt trong cơ thể câu hỏi của bạn. Tôi đã cập nhật câu trả lời của tôi dựa trên nhận xét của bạn.
Anton Trunov

@wvxvw Không nhất thiết, nó có thể chạy mãi mà không làm nổ tung ngăn xếp, miễn là trình biên dịch thực hiện đệ quy đuôi, ví dụ ví dụ của tôi trong OCaml bên dưới không làm nổ stack.
Anton Trunov

1
@AntonTrunov chắc chắn, đó là một cách chơi chữ của tên trang web hơn là một nỗ lực chính xác.
wvxvw

Câu trả lời:


17

Đầu tiên một giải thích thuật ngữ: vị trí tiêu cựctích cực đến từ logic. Họ đang chuẩn bị một assymetry trong từ nối logic: trong các cư xử khác với . Một điều tương tự xảy ra trong lý thuyết thể loại, trong đó chúng ta nói tương phảncovariant thay vì tiêu cực và tích cực, tương ứng. Trong vật lý, chúng nói về các đại lượng ứng xử "covariantly" và "contravariantly. Vì vậy, đây là một hiện tượng rất chung. Một lập trình viên có thể nghĩ chúng là" đầu vào "và" đầu ra ".Một BABAB

Bây giờ vào kiểu dữ liệu quy nạp.

Hãy nghĩ về một kiểu dữ liệu quy nạp như một loại cấu trúc đại số: nhà xây dựng là những hoạt động mà mất yếu tố của như các đối số và sản xuất các yếu tố mới của . Điều này rất giống với đại số thông thường: phép cộng có hai số và tạo ra một số.T T TTTT

Trong đại số, theo thông lệ, một phép toán có số lượng đối số hữu hạn và trong hầu hết các trường hợp, nó cần 0 (hằng số), một (không chính thức) hoặc hai đối số (nhị phân). Thật thuận tiện để khái quát hóa điều này cho các nhà xây dựng của kiểu dữ liệu. Giả sử clà một hàm tạo cho kiểu dữ liệu T:

  • nếu clà một hằng số chúng ta có thể nghĩ về nó như là một hàm unit -> T, hoặc tương đương (empty -> T) -> T,
  • nếu clà unary chúng ta có thể nghĩ về nó như là một hàm T -> T, hoặc tương đương (unit -> T) -> T,
  • nếu clà nhị phân, chúng ta có thể nghĩ về nó như là một hàm T -> T -> T, hoặc tương đương T * T -> T, hoặc tương đương (bool -> T) -> T,
  • nếu chúng ta muốn một hàm tạo ccó bảy đối số, chúng ta có thể xem nó như là một hàm (seven -> T) -> Ttrong đó sevenmột số loại được xác định trước đó với bảy phần tử.
  • chúng ta cũng có thể có một hàm tạo ccó vô số đối số, đó sẽ là một hàm (nat -> T) -> T.

Những ví dụ này cho thấy hình thức chung của một nhà xây dựng nên là

c : (A -> T) -> T

trong đó chúng ta gọi Aarity của cvà chúng ta nghĩ về cmột hàm tạo có Anhiều đối số kiểu Tđể tạo ra một phần tử của T.

Đây là một điều rất quan trọng: các yếu tố phải được xác định trước khi chúng ta xác định T, hoặc nếu không chúng ta không thể nói những gì các nhà xây dựng phải làm. Nếu ai đó cố gắng có một nhà xây dựng

broken: (T -> T) -> T

sau đó câu hỏi "có bao nhiêu đối số broken?" không có câu trả lời hay Bạn có thể cố gắng trả lời nó bằng "cần Tnhiều đối số", nhưng điều đó sẽ không xảy ra, vì Tchưa được xác định. Chúng ta có thể cố gắng thoát khỏi cunundrum bằng cách sử dụng lý thuyết điểm cố định ưa thích để tìm một loại Tvà hàm tiêm (T -> T) -> T, và sẽ thành công, nhưng chúng ta cũng sẽ phá vỡ nguyên tắc cảm ứng Ttrên đường đi. Vì vậy, đó chỉ là một ý tưởng tồi để thử một điều như vậy.

Để hoàn thiện, hãy để tôi giải thích toàn bộ câu chuyện. Chúng ta cần khái quát các hình thức xây dựng ở trên một chút. Đôi khi chúng ta có các hoạt động hoặc hàm tạo lấy tham số . Ví dụ, phép nhân vô hướng lấy vô hướng và vectơ để tạo ra vectơ . Đây là một phép toán đơn phương trên các vectơ, được tham số hóa bởi một vô hướng. Chúng ta có thể xem phép nhân vô hướng là vô số các phép toán đơn nguyên, một phép toán cho mỗi vô hướng, nhưng điều đó gây khó chịu. Vì vậy, dạng chung của một hàm tạo nên cho phép một tham số thuộc loại nào đó :v λ vλvλvcB

c : B * (A -> T) -> T

Trên thực tế, nhiều nhà xây dựng có thể được viết lại theo cách này, nhưng không phải tất cả, chúng tôi cần thêm một bước, cụ thể là chúng ta nên cho phép Ađể phụ thuộc vào B:

c : (∑ (x : B), A x -> T) -> T

Đây là hình thức cuối cùng của một hàm tạo cho kiểu quy nạp. Nó cũng chính xác là loại W là gì. Biểu mẫu rất chung chung đến nỗi chúng ta chỉ cần một nhà xây dựng duy nhất c! Thật vậy, nếu chúng ta có hai trong số họ

d' : (∑ (x : B'), A' x -> T) -> T
d'' : (∑ (x : B''), A'' x -> T) -> T

sau đó chúng ta có thể kết hợp chúng thành một

d : (∑ (x : B), A x -> T) -> T

Ở đâu

B := B' + B''
A(inl x) := A' x
A(inr x) := A'' x

Nhân tiện, nếu chúng ta cà ri hình thức chung, chúng ta thấy rằng nó tương đương với

c : ∏ (x : B), ((A x -> T) -> T)

gần với những gì mọi người thực sự viết ra trong các trợ lý chứng minh. Các trợ lý chứng minh cho phép chúng tôi viết ra các hàm tạo theo những cách thuận tiện, nhưng chúng tương đương với dạng chung ở trên (bài tập!).


1
Cảm ơn một lần nữa Andrej sau bữa trưa của tôi đây sẽ là điều khó khăn nhất để tôi tiêu hóa. Chúc mừng.
Pushpa

9

Sự xuất hiện đầu tiên của Badđược gọi là 'phủ định' vì nó đại diện cho một đối số hàm, tức là nằm ở bên trái của mũi tên hàm (xem các kiểu đệ quy miễn phí của Philip Wadler). Tôi đoán nguồn gốc của thuật ngữ 'tiêu cực vị trí' bắt nguồn từ khái niệm contravariance ( 'Contra' có nghĩa là ngược lại).

Không được phép để loại được xác định ở vị trí phủ định bởi vì người ta có thể viết các chương trình không kết thúc bằng cách sử dụng nó, tức là chuẩn hóa mạnh thất bại trong sự hiện diện của nó (nhiều hơn về điều này dưới đây). Nhân tiện, đây là lý do cho tên của quy tắc 'tính tích cực nghiêm ngặt': chúng tôi không cho phép các vị trí tiêu cực.

Chúng tôi cho phép xuất hiện lần thứ hai Badvì nó không gây ra sự chấm dứt và chúng tôi muốn sử dụng kiểu được xác định ( Bad) tại một số điểm trong kiểu dữ liệu đệ quy ( trước mũi tên cuối cùng của hàm tạo của nó).

Điều quan trọng là phải hiểu rằng định nghĩa sau đây không vi phạm quy tắc tích cực nghiêm ngặt.

data Good : Set where
  good : Good → Good → Good

Quy tắc chỉ áp dụng cho các đối số của nhà xây dựng (cả Goodtrong trường hợp này) và không áp dụng cho chính nhà xây dựng (xem thêm " Lập trình được chứng nhận với các loại phụ thuộc " của Adam Chlipala ).

Một ví dụ khác vi phạm tính tích cực nghiêm ngặt:

data Strange : Set where
  strange : ((Bool → Strange) → (ℕ → Strange)) → Strange
                       ^^     ^
            this Strange is   ...this arrow
            to the left of... 

Bạn cũng có thể muốn kiểm tra câu trả lời này về các vị trí tiêu cực.


Thông tin thêm về việc không chấm dứt ... Trang mà bạn tham chiếu chứa một số giải thích (cùng với một ví dụ trong Haskell):

Các khai báo không tích cực bị từ chối vì người ta có thể viết một hàm không kết thúc bằng cách sử dụng chúng. Để xem làm thế nào người ta có thể viết một định nghĩa lặp bằng cách sử dụng kiểu dữ liệu Bad từ phía trên, hãy xem BadInHaskell .

Dưới đây là một ví dụ tương tự trong Ocaml, cho thấy cách thực hiện hành vi đệ quy mà không cần (!) Sử dụng đệ quy trực tiếp:

type boxed_fun =
  | Box of (boxed_fun -> boxed_fun)

(* (!) in Ocaml the 'let' construct does not permit recursion;
   one have to use the 'let rec' construct to bring 
   the name of the function under definition into scope
*)
let nonTerminating (bf:boxed_fun) : boxed_fun =
  match bf with
    Box f -> f bf

let loop = nonTerminating (Box nonTerminating)

Các nonTerminatingchức năng "giải nén" một hàm từ lý luận và táo của nó để lập luận ban đầu. Điều quan trọng ở đây là hầu hết các hệ thống loại không cho phép truyền các chức năng cho chính chúng, vì vậy một thuật ngữ như f fsẽ không đánh máy, vì không có loại nào fđể thỏa mãn trình đánh máy. Một trong những lý do hệ thống loại được giới thiệu là để vô hiệu hóa tự ứng dụng (xem tại đây ).

Gói các kiểu dữ liệu như kiểu mà chúng tôi đã giới thiệu ở trên có thể được sử dụng để phá vỡ rào cản này trên đường đến sự không nhất quán.

Tôi muốn thêm rằng các tính toán không kết thúc giới thiệu sự không nhất quán cho các hệ thống logic. Trong trường hợp Agda và Coq, Falsekiểu dữ liệu quy nạp không có bất kỳ hàm tạo nào, vì vậy bạn không bao giờ có thể xây dựng một thuật ngữ chứng minh loại Sai. Nhưng nếu tính toán không kết thúc được cho phép, người ta có thể làm điều đó ví dụ theo cách này (trong Coq):

Fixpoint loop (n : nat) : False = loop n

Sau đó, đánh máy loop 0sẽ đưa ra loop 0 : False, do đó, theo thư của Curry-Howard, điều đó có nghĩa là chúng tôi đã chứng minh một đề xuất sai.

Upshot : quy tắc tích cực nghiêm ngặt cho các định nghĩa quy nạp ngăn chặn các tính toán không kết thúc gây tai hại cho logic.


Bây giờ tôi đang bối rối. Dữ liệu đặc biệt Tốt: Đặt nơi tốt: Tốt → Tốt →. Chúng tôi sẽ cố gắng hiểu và quay lại sau một giờ /
Pushpa

Quy tắc không áp dụng cho chính hàm tạo, chỉ áp dụng cho các đối số của nó, tức là các mũi tên ở cấp cao nhất của định nghĩa hàm tạo không quan trọng. Tôi cũng đã thêm một ví dụ vi phạm (gián tiếp).
Anton Trunov
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.