Có trường hợp sử dụng nào cho loại dưới cùng như một loại tham số chức năng không?


12

Nếu một hàm có kiểu trả về ( kiểu dưới cùng ), điều đó có nghĩa là nó không bao giờ trả về. Nó có thể ví dụ như thoát hoặc ném, cả hai tình huống khá bình thường.

Có lẽ nếu một hàm có tham số kiểu thì nó không bao giờ có thể được gọi (một cách an toàn). Có bao giờ bất kỳ lý do để xác định một chức năng như vậy?

Câu trả lời:


17

Một trong những đặc tính xác định của hoặc gõ trống là có tồn tại một hàm cho tất cả các loại . Trong thực tế, tồn tại một chức năng duy nhất như vậy. Do đó, khá hợp lý khi chức năng này được cung cấp như một phần của thư viện chuẩn. Thường thì nó được gọi là một cái gì đó như . (Trong các hệ thống với subtyping, điều này có thể được xử lý chỉ đơn giản bằng cách là một subtype của tất cả các loại. Sau đó, chuyển đổi ngầm là . Một cách tiếp cận liên quan là để xác định như mà chỉ đơn giản có thể được khởi tạo để bất kỳ loại nào.)MộtMộtalpha . αabsurdabsurd α.α

Bạn chắc chắn muốn có một chức năng như vậy hoặc tương đương vì đó là những gì cho phép bạn sử dụng các chức năng tạo ra . Ví dụ, chúng ta hãy nói rằng tôi đang cung cấp một loại tổng hợp . Tôi thực hiện phân tích trường hợp về nó và trong trường hợp tôi sẽ đưa ra một ngoại lệ bằng cách sử dụng . Trong trường hợp, tôi sẽ sử dụng . Nói chung, tôi muốn có một giá trị của loại vì vậy tôi cần phải làm gì đó để biến một thành . Đó là những gì sẽ cho phép tôi làm.E+MộtEthrow:EMộtf:MộtBBBabsurd

Điều đó nói rằng, không có một toàn bộ rất nhiều lý do để xác định chức năng của riêng bạn . Theo định nghĩa, chúng nhất thiết phải là trường hợp của . Tuy nhiên, bạn có thể làm điều đó nếu không được thư viện tiêu chuẩn cung cấp hoặc bạn muốn có một phiên bản chuyên biệt để hỗ trợ kiểm tra / suy luận kiểu. Bạn có thể, tuy nhiên, dễ dàng tạo chức năng mà sẽ kết thúc khởi tạo cho một loại như .MộtAabsurdabsurdMột

Mặc dù không có nhiều lý do để viết một hàm như vậy, nhưng nhìn chung nó vẫn được cho phép . Một lý do là nó đơn giản hóa các công cụ / macro tạo mã.


Vì vậy, điều này có nghĩa là một cái gì đó như (x ? 3 : throw new Exception())được thay thế cho mục đích phân tích với một cái gì đó giống như (x ? 3 : absurd(throw new Exception()))?
bdsl

Nếu bạn không có phân nhóm hoặc chưa xác định là , thì cái trước sẽ không kiểm tra và cái sau sẽ kiểm tra. Với phân nhóm, vâng, một cái gì đó giống như sẽ được chèn vào. Tất nhiên, bạn có thể đặt định nghĩa bên trong định nghĩa chính xác việc xác định là sẽ làm gì. α . alpha alpha . αα.αabsurdabsurdthrowα.α
Derek Elkins rời SE

6

Để thêm vào những gì đã nói về chức năng absurd: ⊥ -> atôi có một ví dụ cụ thể về nơi chức năng này thực sự hữu ích.

Hãy xem xét kiểu dữ liệu Haskell Free f ađại diện cho cấu trúc cây chung với fcác nút và lá có hình chữ as chứa s:

data Free f a = Op (f (Free f a)) | Var a

Những cây này có thể được gấp lại với chức năng sau:

fold :: Functor f => (a -> b) -> (f b -> b) -> Free f a -> b
fold gen alg (Var x) = gen x
fold gen alg (Op x) = alg (fmap (fold gen alg) x)

Tóm lại, hoạt động này đặt algtại các nút và gentại lá.

Bây giờ đến điểm: tất cả các cơ sở dữ liệu đệ quy có thể được biểu diễn bằng kiểu dữ liệu điểm cố định. Trong Haskell, đây là Fix fvà nó có thể được định nghĩa là type Fix f = Free f ⊥(tức là Cây có fcác nút có hình và không có lá bên ngoài functor f). Theo truyền thống, cấu trúc này cũng có một nếp gấp, được gọi là cata:

cata :: Functor f => (f a -> a) -> Fix f -> a
cata alg x = fold absurd alg x

Điều này mang lại một cách sử dụng khá gọn gàng vô lý: vì cây không thể có bất kỳ lá nào (vì không có cư dân nào khác undefined), nên không bao giờ có thể sử dụng gencho nếp gấp này và absurdminh họa điều đó!


2

Loại dưới cùng là một kiểu con của mọi loại khác, có thể cực kỳ hữu ích trong thực tế. Ví dụ, loại NULLC trong phiên bản lý thuyết - phiên bản an toàn của C phải là một kiểu con của mọi loại con trỏ khác, nếu không, bạn không thể trả về NULLnơi char*dự kiến; tương tự, loại undefinedJavaScript trong loại lý thuyết an toàn phải là một kiểu con của mọi loại khác trong ngôn ngữ.

Là một kiểu trả về hàm, nó cũng rất hữu ích khi có một số hàm không bao giờ trả về. Trong một ngôn ngữ được gõ mạnh với các ngoại lệ, ví dụ, loại nào nên exit()hoặc throw()trả về? Họ không bao giờ trả lại dòng điều khiển cho người gọi của họ. Và vì loại dưới cùng là một kiểu con của mọi loại khác, nên nó hoàn toàn hợp lệ cho một hàm quay trở lại Intthay vì trả về Nottthat, một hàm trả về cũng có thể chọn hoàn toàn không trả về. (Có thể nó gọi , hoặc có thể nó đi vào một vòng lặp vô hạn.) Điều này là tốt để có, bởi vì một hàm có bao giờ trả lại hay không là nổi tiếng không thể giải quyết được.Intexit()

Cuối cùng, nó rất hữu ích cho việc viết các ràng buộc. Giả sử bạn muốn hạn chế tất cả các tham số trên "cả hai bên", cung cấp một loại phải là siêu kiểu của tham số và một loại khác phải là kiểu con. Từ đáy là một subtype của mỗi loại, bạn có thể bày tỏ "bất kỳ subtype của S" như . Hoặc, bạn có thể diễn đạt "bất kỳ loại nào" dưới dạng .TST


3
NULLlà một loại đơn vị không phải nó, khác với đó là loại trống?
bdsl

Tôi không chắc chắn nghĩa là gì trong lý thuyết loại.
bdsl

1
@bdsl Toán tử cong ở đây là "là một kiểu con của"; Tôi không chắc nó có chuẩn không, đó chỉ là những gì giáo sư của tôi đã sử dụng.
Draconis

1
@ gnasher729 Đúng, nhưng C cũng không đặc biệt an toàn. Tôi đang nói nếu bạn không thể truyền một số nguyên cho void*, bạn sẽ cần một loại cụ thể cho số đó có thể được sử dụng cho bất kỳ loại con trỏ nào.
Draconis


2

Có một cách sử dụng mà tôi có thể nghĩ ra, và đó là thứ được coi là một cải tiến cho ngôn ngữ lập trình Swift.

Swift có một maybeMonad, đánh vần Optional<T>hoặc T?. Có nhiều cách để tương tác với nó.

  • Bạn có thể sử dụng unrapping có điều kiện như

    if let nonOptional = someOptional {
        print(nonOptional)
    }
    else {
        print("someOptional was nil")
    }
    
  • Bạn có thể sử dụng map, flatMapđể chuyển đổi các giá trị

  • Toán tử unsrap ( !, loại (T?) -> T) buộc mạnh mẽ mở khóa nội dung, nếu không sẽ gây ra sự cố
  • Toán tử hợp nhất nil ( ??, thuộc loại (T?, T) -> T) để lấy giá trị của nó hoặc sử dụng giá trị mặc định:

    let someI = Optional(100)
    print(someI ?? 123) => 100 // "left operand is non-nil, unwrap it.
    
    let noneI: Int? = nil
    print(noneI ?? 123) // => 123 // left operand is nil, take right operand, acts like a "default" value
    

Thật không may, không có cách nào ngắn gọn để nói "gỡ lỗi hoặc ném lỗi" hoặc "gỡ rối hoặc gặp sự cố với thông báo lỗi tùy chỉnh". Cái gì đó như

let someI: Int? = Optional(123)
let nonOptionalI: Int = someI ?? fatalError("Expected a non-nil value")

không biên dịch, vì fatalErrorcó loại () -> Never( ()Void, loại đơn vị của Swift, Neverlà loại dưới cùng của Swift). Gọi nó là sản xuất Never, không tương thích với Tdự kiến ​​là toán hạng đúng của ??.

Trong nỗ lực khắc phục vấn đề này, Swift Evolution propsoal SE-0217- Nhà điều hành Unwrap hoặc Die Tiết đã được đưa ra. Cuối cùng nó đã bị từ chối , nhưng nó đã làm tăng sự quan tâm trong việc trở Neverthành một kiểu con của tất cả các loại.

Nếu Neverđược tạo thành một kiểu con của tất cả các loại, thì ví dụ trước sẽ có thể biên dịch được:

let someI: Int? = Optional(123)
let nonOptionalI: Int = someI ?? fatalError("Expected a non-nil value")

bởi vì trang web của cuộc gọi ??có loại (T?, Never) -> T, sẽ tương thích với (T?, T) -> Tchữ ký của ??.


0

Swift có một loại "Không bao giờ" có vẻ khá giống với loại dưới cùng: Một hàm được khai báo để trả về Không bao giờ có thể trả về, một hàm có tham số loại Không bao giờ có thể được gọi.

Điều này rất hữu ích khi kết nối với các giao thức, trong đó có thể có một hạn chế do hệ thống loại ngôn ngữ mà một lớp phải có một chức năng nhất định, nhưng không có yêu cầu nào về chức năng này nên được gọi và không yêu cầu loại đối số nào sẽ là

Để biết chi tiết, bạn nên xem qua các bài đăng mới hơn trong danh sách gửi thư tiến hóa nhanh.


7
"Bài viết mới hơn trong danh sách gửi thư tiến hóa nhanh" không phải là một tài liệu tham khảo rất rõ ràng hoặc ổn định. Không có một kho lưu trữ web của danh sách gửi thư?
Derek Elkins rời SE
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.