Hạn chế đơn hình là gì?


78

Tôi bối rối bởi cách trình biên dịch haskell đôi khi đưa ra các kiểu ít đa hình hơn những gì tôi mong đợi, chẳng hạn như khi sử dụng các định nghĩa không có điểm.

Có vẻ như vấn đề là "hạn chế đơn hình", được bật theo mặc định trên các phiên bản cũ hơn của trình biên dịch.

Hãy xem xét chương trình haskell sau:

{-# LANGUAGE MonomorphismRestriction #-}

import Data.List(sortBy)

plus = (+)
plus' x = (+ x)

sort = sortBy compare

main = do
  print $ plus' 1.0 2.0
  print $ plus 1.0 2.0
  print $ sort [3, 1, 2]

Nếu tôi biên dịch điều này với, ghctôi không thu được lỗi nào và đầu ra của tệp thực thi là:

3.0
3.0
[1,2,3]

Nếu tôi thay đổi nội dung mainthành:

main = do
  print $ plus' 1.0 2.0
  print $ plus (1 :: Int) 2
  print $ sort [3, 1, 2]

Tôi không gặp lỗi thời gian biên dịch và đầu ra trở thành:

3.0
3
[1,2,3]

như mong đợi. Tuy nhiên, nếu tôi cố gắng thay đổi nó thành:

main = do
  print $ plus' 1.0 2.0
  print $ plus (1 :: Int) 2
  print $ plus 1.0 2.0
  print $ sort [3, 1, 2]

Tôi gặp lỗi loại:

test.hs:13:16:
    No instance for (Fractional Int) arising from the literal ‘1.0’
    In the first argument of ‘plus’, namely ‘1.0’
    In the second argument of ‘($)’, namely ‘plus 1.0 2.0’
    In a stmt of a 'do' block: print $ plus 1.0 2.0

Điều tương tự cũng xảy ra khi cố gắng gọi sorthai lần với các kiểu khác nhau:

main = do
  print $ plus' 1.0 2.0
  print $ plus 1.0 2.0
  print $ sort [3, 1, 2]
  print $ sort "cba"

tạo ra lỗi sau:

test.hs:14:17:
    No instance for (Num Char) arising from the literal ‘3’
    In the expression: 3
    In the first argument of ‘sort’, namely ‘[3, 1, 2]’
    In the second argument of ‘($)’, namely ‘sort [3, 1, 2]’
  • Tại sao ghcđột nhiên nghĩ rằng đó pluskhông phải là đa hình và yêu cầu một Intđối số? Tham chiếu duy nhất đến Intlà trong một ứng dụng của plus, làm thế nào điều đó có thể quan trọng khi định nghĩa rõ ràng là đa hình?
  • Tại sao ghcđột nhiên nghĩ rằng sortcần một Num Chartrường hợp?

Hơn nữa, nếu tôi cố gắng đặt các định nghĩa hàm vào mô-đun riêng của chúng, như trong:

{-# LANGUAGE MonomorphismRestriction #-}

module TestMono where

import Data.List(sortBy)

plus = (+)
plus' x = (+ x)

sort = sortBy compare

Tôi gặp lỗi sau khi biên dịch:

TestMono.hs:10:15:
    No instance for (Ord a0) arising from a use of ‘compare’
    The type variable ‘a0’ is ambiguous
    Relevant bindings include
      sort :: [a0] -> [a0] (bound at TestMono.hs:10:1)
    Note: there are several potential instances:
      instance Integral a => Ord (GHC.Real.Ratio a)
        -- Defined in ‘GHC.Real’
      instance Ord () -- Defined in ‘GHC.Classes’
      instance (Ord a, Ord b) => Ord (a, b) -- Defined in ‘GHC.Classes’
      ...plus 23 others
    In the first argument of ‘sortBy’, namely ‘compare’
    In the expression: sortBy compare
    In an equation for ‘sort’: sort = sortBy compare
  • Tại sao không ghcthể sử dụng kiểu đa hình Ord a => [a] -> [a]cho sort?
  • Và tại sao ghcđiều trị plusplus'khác nhau? plusnên có kiểu đa hình Num a => a -> a -> avà tôi không thực sự thấy điều này khác với kiểu của sortvà chỉ sortgây ra lỗi.

Điều cuối cùng: nếu tôi nhận xét định nghĩa của sortcác biên dịch tệp. Tuy nhiên, nếu tôi cố gắng tải nó vào ghcivà kiểm tra các loại tôi nhận được:

*TestMono> :t plus
plus :: Integer -> Integer -> Integer
*TestMono> :t plus'
plus' :: Num a => a -> a -> a

Tại sao không phải là loại cho plusđa hình?


Đây là câu hỏi kinh điển về hạn chế đơn hình trong Haskell như đã thảo luận trong câu hỏi meta .


Tại sao thông báo dịch vụ công đột ngột? Ngoài ra, tôi nghĩ rằng "tắt nó đi" có lẽ nên được đề xuất nổi bật hơn trong câu trả lời của bạn.
dfeuer

2
@dfeuer Đột ngột? Câu hỏi meta đã được hỏi 4 tháng trước . Tôi đã đăng một bản nháp của câu trả lời dưới đây 2 tuần trước . Tôi cũng đã đề cập đến cả hai sự kiện này trong cuộc trò chuyện cách đây khá lâu. Đối với tôi, điều này không phải là "đột ngột". Ngày mai, tôi sẽ xem tôi có thể làm gì để đánh dấu thông tin quan trọng nhất.
Bakuriu

1
Ah, tôi đã bỏ lỡ tham chiếu meta.
dfeuer

Câu trả lời:


103

Hạn chế đơn hình là gì?

Các hạn chế monomorphism như đã nêu bởi Haskell wiki là:

một quy tắc phản trực giác trong suy luận kiểu Haskell. Nếu bạn quên cung cấp chữ ký kiểu, đôi khi quy tắc này sẽ điền vào các biến kiểu tự do với các kiểu cụ thể bằng cách sử dụng quy tắc "kiểu mặc định".

Điều này có nghĩa là, trong một số trường hợp , nếu kiểu của bạn không rõ ràng (tức là đa hình), trình biên dịch sẽ chọn để khởi tạo kiểu đó thành một thứ không mơ hồ.

Làm thế nào để tôi sửa chữa nó?

Trước hết, bạn luôn có thể cung cấp một cách rõ ràng chữ ký loại và điều này sẽ tránh việc kích hoạt hạn chế:

plus :: Num a => a -> a -> a
plus = (+)    -- Okay!

-- Runs as:
Prelude> plus 1.0 1
2.0

Ngoài ra, nếu bạn đang xác định một hàm, bạn có thể tránh kiểu khôngdấu chấm và ví dụ: viết:

plus x y = x + y

Tắt nó đi

Có thể chỉ cần tắt hạn chế để bạn không phải làm gì với mã của mình để sửa nó. Hành vi được kiểm soát bởi hai phần mở rộng: MonomorphismRestrictionsẽ kích hoạt nó (là mặc định) trong khi NoMonomorphismRestrictionsẽ tắt nó.

Bạn có thể đặt dòng sau ở đầu tệp của mình:

{-# LANGUAGE NoMonomorphismRestriction #-}

Nếu bạn đang sử dụng GHCi, bạn có thể bật tiện ích mở rộng này bằng :setlệnh:

Prelude> :set -XNoMonomorphismRestriction

Bạn cũng có thể yêu ghccầu bật tiện ích mở rộng từ dòng lệnh:

ghc ... -XNoMonomorphismRestriction

Lưu ý: Bạn thực sự nên thích tùy chọn đầu tiên hơn là chọn tiện ích mở rộng thông qua các tùy chọn dòng lệnh.

Tham khảo trang của GHC để biết giải thích về điều này và các phần mở rộng khác.

Một lời giải thích đầy đủ

Tôi sẽ cố gắng tóm tắt bên dưới mọi thứ bạn cần biết để hiểu giới hạn đơn hình là gì, tại sao nó được giới thiệu và cách nó hoạt động.

Một ví dụ

Hãy định nghĩa tầm thường sau đây:

plus = (+)

bạn nghĩ có thể thay thế mọi lần xuất hiện +bằng plus. Đặc biệt vì (+) :: Num a => a -> a -> abạn cũng muốn có plus :: Num a => a -> a -> a.

Không may, không phải trường hợp này. Ví dụ trong chúng tôi thử như sau trong GHCi:

Prelude> let plus = (+)
Prelude> plus 1.0 1

Chúng tôi nhận được kết quả sau:

<interactive>:4:6:
    No instance for (Fractional Integer) arising from the literal ‘1.0’
    In the first argument of ‘plus’, namely ‘1.0’
    In the expression: plus 1.0 1
    In an equation for ‘it’: it = plus 1.0 1

Bạn có thể cần đến :set -XMonomorphismRestriction các phiên bản GHCi mới hơn.

Và trên thực tế, chúng ta có thể thấy rằng kiểu pluskhông như chúng ta mong đợi:

Prelude> :t plus
plus :: Integer -> Integer -> Integer

Điều đã xảy ra là trình biên dịch đã thấy rằng pluscó kiểu Num a => a -> a -> a, một kiểu đa hình. Hơn nữa, nó xảy ra rằng định nghĩa trên nằm dưới các quy tắc mà tôi sẽ giải thích sau và vì vậy anh ấy quyết định tạo kiểu đơn hình bằng cách đặt mặc định cho biến kiểu a. Mặc định là Integernhư chúng ta có thể thấy.

Lưu ý rằng nếu bạn cố gắng biên dịch mã trên bằng cách sử dụng, ghcbạn sẽ không gặp bất kỳ lỗi nào. Điều này là do cách ghcixử lý (và phải xử lý) các định nghĩa tương tác. Về cơ bản, mọi câu lệnh được nhập vào ghciphải được đánh dấu hoàn toàn trước khi xem xét phần sau; nói cách khác, nó như thể mọi câu lệnh nằm trong một mô-đun riêng biệt . Sau này tôi sẽ giải thích lý do tại sao vấn đề này.

Một số ví dụ khác

Hãy xem xét các định nghĩa sau:

f1 x = show x

f2 = \x -> show x

f3 :: (Show a) => a -> String
f3 = \x -> show x

f4 = show

f5 :: (Show a) => a -> String
f5 = show

Chúng tôi mong muốn tất cả các chức năng này để hành xử theo cách tương tự và có cùng loại, tức là các loại show: Show a => a -> String.

Tuy nhiên, khi biên dịch các định nghĩa trên, chúng tôi gặp các lỗi sau:

test.hs:3:12:
    No instance for (Show a1) arising from a use of ‘show’
    The type variable ‘a1’ is ambiguous
    Relevant bindings include
      x :: a1 (bound at blah.hs:3:7)
      f2 :: a1 -> String (bound at blah.hs:3:1)
    Note: there are several potential instances:
      instance Show Double -- Defined in ‘GHC.Float’
      instance Show Float -- Defined in ‘GHC.Float’
      instance (Integral a, Show a) => Show (GHC.Real.Ratio a)
        -- Defined in ‘GHC.Real’
      ...plus 24 others
    In the expression: show x
    In the expression: \ x -> show x
    In an equation for ‘f2’: f2 = \ x -> show x

test.hs:8:6:
    No instance for (Show a0) arising from a use of ‘show’
    The type variable ‘a0’ is ambiguous
    Relevant bindings include f4 :: a0 -> String (bound at blah.hs:8:1)
    Note: there are several potential instances:
      instance Show Double -- Defined in ‘GHC.Float’
      instance Show Float -- Defined in ‘GHC.Float’
      instance (Integral a, Show a) => Show (GHC.Real.Ratio a)
        -- Defined in ‘GHC.Real’
      ...plus 24 others
    In the expression: show
    In an equation for ‘f4’: f4 = show

Vì vậy f2f4không biên dịch. Hơn nữa, khi cố gắng xác định các hàm này trong GHCi, chúng tôi không gặp lỗi , nhưng loại cho f2f4() -> String!

Monomorphism hạn chế là những gì làm f2f4đòi hỏi một loại monomorphic, và bewteen hành vi khác nhau ghcghcilà do khác nhau quy tắc mặc định .

Khi nào nó xảy ra?

Trong Haskell, như được định nghĩa bởi báo cáo , có hai loại ràng buộc riêng biệt . Ràng buộc hàm và ràng buộc mẫu. Một liên kết hàm không là gì khác hơn là một định nghĩa của một hàm:

f x = x + 1

Lưu ý rằng cú pháp của chúng là:

<identifier> arg1 arg2 ... argn = expr

Modulo bảo vệ và wheretuyên bố. Nhưng chúng không thực sự quan trọng.

trong đó phải có ít nhất một đối số .

Một liên kết mẫu là một khai báo của biểu mẫu:

<pattern> = expr

Một lần nữa, những người bảo vệ modulo.

Lưu ý rằng các biến là các mẫu , vì vậy ràng buộc:

plus = (+)

là một ràng buộc mẫu . Nó liên kết mẫu plus(một biến) với biểu thức (+).

Khi ràng buộc mẫu chỉ bao gồm một tên biến, nó được gọi là ràng buộc mẫu đơn giản .

Hạn chế đơn hình áp dụng cho các liên kết mẫu đơn giản!

Vâng, chính thức chúng ta nên nói rằng:

Nhóm khai báo là một tập hợp tối thiểu các ràng buộc phụ thuộc lẫn nhau.

Mục 4.5.1 của báo cáo .

Và sau đó (Phần 4.5.5 của báo cáo ):

một nhóm khai báo nhất định không bị hạn chế nếu và chỉ khi:

  1. mọi biến trong nhóm được ràng buộc bởi một ràng buộc hàm (ví dụ f x = x) hoặc một ràng buộc mẫu đơn giản (ví dụ: plus = (+)Phần 4.4.3.2), và

  2. một chữ ký kiểu rõ ràng được đưa ra cho mọi biến trong nhóm được ràng buộc bởi ràng buộc mẫu đơn giản. (vd plus :: Num a => a -> a -> a; plus = (+)).

Ví dụ do tôi thêm vào.

Vì vậy, nhóm khai báo hạn chế là một nhóm có các ràng buộc mẫu không đơn giản (ví dụ (x:xs) = f somethinghoặc (f, g) = ((+), (-))) hoặc có một số ràng buộc mẫu đơn giản không có chữ ký kiểu (như trong plus = (+)).

Hạn chế đơn hình ảnh hưởng đến các nhóm khai báo bị hạn chế .

Hầu hết thời gian bạn không xác định các hàm đệ quy lẫn nhau và do đó một nhóm khai báo chỉ trở thành một ràng buộc.

Nó làm gì?

Hạn chế về tính đơn hình được mô tả bởi hai quy tắc trong Phần 4.5.5 của báo cáo .

Quy tắc đầu tiên

Hạn chế thông thường của Hindley-Milner đối với tính đa hình là chỉ những biến kiểu không xảy ra tự do trong môi trường mới có thể được tổng quát hóa. Ngoài ra, các biến kiểu hạn chế của một nhóm khai báo hạn chế có thể không được tổng quát hóa trong bước tổng quát hóa cho nhóm đó. (Nhớ lại rằng biến kiểu bị ràng buộc nếu nó phải thuộc một lớp kiểu nào đó; xem Phần 4.5.2.)

Phần được đánh dấu là những gì giới hạn tính đơn hình giới thiệu. Nó nói rằng nếu kiểu là đa hình (tức là nó chứa một số biến kiểu) biến kiểu đó bị ràng buộc (nghĩa là nó có ràng buộc về lớp: ví dụ kiểu Num a => a -> a -> alà đa hình vì nó chứa avà cũng tương phản vì acó ràng buộc Numđối với nó .) thì không thể khái quát được.

Nói một cách đơn giản, không khái quát hóa có nghĩa là việc sử dụng hàm pluscó thể thay đổi kiểu của nó.

Nếu bạn có các định nghĩa:

plus = (+)

x :: Integer
x = plus 1 2

y :: Double
y = plus 1.0 2

thì bạn sẽ gặp lỗi loại. Bởi vì khi trình biên dịch thấy điều đó plusđược gọi qua một Integertrong khai báo của xnó sẽ thống nhất biến kiểu avới Integervà do đó kiểu plustrở thành:

Integer -> Integer -> Integer

nhưng sau đó, khi nó gõ, hãy kiểm tra định nghĩa của y, nó sẽ thấy định nghĩa đó plus được áp dụng cho một Doubleđối số và các kiểu không khớp.

Lưu ý rằng bạn vẫn có thể sử dụng plusmà không gặp lỗi:

plus = (+)
x = plus 1.0 2

Trong trường hợp này, kiểu plusđầu tiên được suy ra là Num a => a -> a -> a nhưng sau đó việc sử dụng nó trong định nghĩa x, nơi 1.0yêu cầu một Fractional ràng buộc, sẽ thay đổi nó thành Fractional a => a -> a -> a.

Cơ sở lý luận

Báo cáo cho biết:

Quy tắc 1 được yêu cầu vì hai lý do, cả hai đều khá tinh tế.

  • Quy tắc 1 ngăn các phép tính lặp lại bất ngờ. Ví dụ: genericLengthlà một hàm chuẩn (trong thư viện Data.List) có kiểu được cung cấp bởi

    genericLength :: Num a => [b] -> a
    

    Bây giờ hãy xem xét biểu thức sau:

    let len = genericLength xs
    in (len, len)
    

    Có vẻ như lenchỉ nên được tính một lần, nhưng nếu không có Quy tắc 1, nó có thể được tính hai lần, một lần ở mỗi trong số hai lần nạp chồng khác nhau. Nếu lập trình viên thực sự muốn tính toán được lặp lại, một chữ ký kiểu rõ ràng có thể được thêm vào:

    let len :: Num a => a
        len = genericLength xs
    in (len, len)
    

Về điểm này, ví dụ từ wiki , tôi tin là rõ ràng hơn. Xem xét chức năng:

f xs = (len, len)
  where
    len = genericLength xs

Nếu lenlà đa hình, kiểu của fsẽ là:

f :: Num a, Num b => [c] -> (a, b)

Vì vậy, hai phần tử của tuple (len, len)thực sự có thể là các giá trị khác nhau ! Nhưng điều này có nghĩa là tính toán được thực hiện bởi genericLength phải được lặp lại để thu được hai giá trị khác nhau.

Cơ sở lý luận ở đây là: mã chứa một lệnh gọi hàm, nhưng không giới thiệu quy tắc này có thể tạo ra hai lệnh gọi hàm ẩn, điều này phản trực quan.

Với hạn chế đơn hình, kiểu ftrở thành:

f :: Num a => [b] -> (a, a)

Theo cách này, không cần phải thực hiện tính toán nhiều lần.

  • Quy tắc 1 ngăn chặn sự mơ hồ. Ví dụ, hãy xem xét nhóm khai báo

    [(n, s)] = đọc t

    Nhớ lại rằng đó readslà một hàm tiêu chuẩn có kiểu được cung cấp bởi chữ ký

    lần đọc :: (Đọc a) => Chuỗi -> [(a, Chuỗi)]

    Nếu không có Quy tắc 1, nsẽ được chỉ định kiểu ∀ a. Read a ⇒ as kiểu ∀ a. Read a ⇒ String. Loại thứ hai là một loại không hợp lệ, bởi vì nó vốn không rõ ràng. Không thể xác định sử dụng quá tải ở mức nào s, cũng như không thể giải quyết điều này bằng cách thêm chữ ký kiểu cho s. Do đó, khi các ràng buộc mẫu không đơn giản được sử dụng (Phần 4.4.3.2), các kiểu được suy ra luôn là đơn hình trong các biến kiểu ràng buộc của chúng, bất kể có cung cấp chữ ký kiểu hay không. Trong trường hợp này, cả hai nsđều là đơn hình trong a.

Vâng, tôi tin rằng ví dụ này là tự giải thích. Có những tình huống khi không áp dụng quy tắc dẫn đến sự mơ hồ về kiểu.

Nếu bạn tắt tiện ích mở rộng như đề xuất ở trên, bạn sẽ gặp lỗi loại khi cố gắng biên dịch khai báo ở trên. Tuy nhiên, đây thực sự không phải là vấn đề: bạn đã biết rằng khi sử dụng readbạn phải bằng cách nào đó cho trình biên dịch biết loại mà nó sẽ cố gắng phân tích cú pháp ...

Quy tắc thứ hai

  1. Bất kỳ biến kiểu đơn hình nào vẫn còn khi suy luận kiểu cho toàn bộ mô-đun hoàn tất, được coi là không rõ ràng và được giải quyết thành các kiểu cụ thể bằng cách sử dụng các quy tắc mặc định (Phần 4.3.4).

Điều này có nghĩa rằng. Nếu bạn có định nghĩa thông thường của mình:

plus = (+)

Điều này sẽ có một loại Num a => a -> a -> aalà một monomorphic kiểu biến do để cai trị 1 mô tả ở trên. Khi toàn bộ mô-đun được suy ra, trình biên dịch sẽ chỉ cần chọn một kiểu thay thế kiểu đó a theo các quy tắc mặc định.

Kết quả cuối cùng là: plus :: Integer -> Integer -> Integer.

Lưu ý rằng điều này được thực hiện sau khi toàn bộ mô-đun được suy ra.

Điều này có nghĩa là nếu bạn có các khai báo sau:

plus = (+)

x = plus 1.0 2.0

bên trong một mô-đun, trước khi nhập, mặc định loại plussẽ là: Fractional a => a -> a -> a(xem quy tắc 1 để biết lý do tại sao điều này xảy ra). Tại thời điểm này, tuân theo các quy tắc mặc định, asẽ được thay thế bằng Double và vì vậy chúng ta sẽ có plus :: Double -> Double -> Doublex :: Double.

Mặc định

Như đã nêu trước khi tồn tại một số quy tắc mặc định, được mô tả trong Phần 4.3.4 của Báo cáo , mà người giả mạo có thể áp dụng và điều đó sẽ thay thế một kiểu đa hình bằng một kiểu đơn hình. Điều này xảy ra bất cứ khi nào một kiểu không rõ ràng .

Ví dụ trong biểu thức:

let x = read "<something>" in show x

ở đây biểu thức không rõ ràng vì các loại cho showreadlà:

show :: Show a => a -> String
read :: Read a => String -> a

Vì vậy, xloại có Read a => a. Nhưng hạn chế này được thỏa mãn bởi rất nhiều loại: Int, Doublehoặc ()ví dụ. Chọn cái nào? Không có gì có thể cho chúng tôi biết.

Trong trường hợp này, chúng ta có thể giải quyết sự không rõ ràng bằng cách cho trình biên dịch biết kiểu nào chúng ta muốn, thêm một chữ ký kiểu:

let x = read "<something>" :: Int in show x

Bây giờ vấn đề là: vì Haskell sử dụng Numlớp kiểu để xử lý số, nên có rất nhiều trường hợp biểu thức số chứa sự mơ hồ.

Xem xét:

show 1

Kết quả phải là gì?

Như trước đây 1có loại Num a => avà có nhiều loại số có thể được sử dụng. Chọn cái nào?

Việc gặp lỗi trình biên dịch hầu như mỗi khi chúng ta sử dụng một số không phải là điều tốt, và do đó các quy tắc mặc định đã được đưa ra. Các quy tắc có thể được kiểm soát bằng cách sử dụng một defaultkhai báo. Bằng cách chỉ định, default (T1, T2, T3)chúng ta có thể thay đổi cách kẻ giả mạo mặc định các loại khác nhau.

Một biến kiểu không rõ ràng vcó thể mặc định được nếu:

  • vchỉ xuất hiện trong contraints của các loại C vđã Clà một lớp (tức là nếu nó xuất hiện như trong: Monad (m v)sau đó nó là không defaultable).
  • ít nhất một trong những lớp này là Numhoặc một lớp con của Num.
  • tất cả các lớp này được định nghĩa trong Prelude hoặc một thư viện chuẩn.

Một biến kiểu có thể mặc định được thay thế bằng kiểu đầu tiên trong defaultdanh sách là một thể hiện của tất cả các lớp của biến không rõ ràng.

defaultKhai báo mặc định là default (Integer, Double).

Ví dụ:

plus = (+)
minus = (-)

x = plus 1.0 1
y = minus 2 1

Các loại được suy ra sẽ là:

plus :: Fractional a => a -> a -> a
minus :: Num a => a -> a -> a

mà theo các quy tắc mặc định, trở thành:

plus :: Double -> Double -> Double
minus :: Integer -> Integer -> Integer

Lưu ý rằng điều này giải thích tại sao trong ví dụ trong câu hỏi chỉ có sort định nghĩa nêu ra lỗi. Loại Ord a => [a] -> [a]không thể được đặt mặc định vì Ordkhông phải là một lớp số.

Mặc định mở rộng

Lưu ý rằng GHCi đi kèm với các quy tắc mặc định mở rộng (hoặc ở đây là GHC8 ), có thể được bật trong tệp cũng như sử dụng các ExtendedDefaultRulesphần mở rộng.

Các biến kiểu defaultable không cần phải chỉ xuất hiện trong contraints nơi mà tất cả các lớp học là tiêu chuẩn và phải có ít nhất một lớp đó là một trong những Eq, Ord, Showhay Numvà lớp con của nó.

Hơn nữa defaultkhai báo mặc định là default ((), Integer, Double).

Điều này có thể tạo ra kết quả kỳ lạ. Lấy ví dụ từ câu hỏi:

Prelude> :set -XMonomorphismRestriction
Prelude> import Data.List(sortBy)
Prelude Data.List> let sort = sortBy compare
Prelude Data.List> :t sort
sort :: [()] -> [()]

trong ghci, chúng tôi không gặp lỗi kiểu nhưng các Ord aràng buộc dẫn đến một lỗi mặc định ()là vô dụng.

Liên kết hữu ích

rất nhiều tài nguyên và thảo luận về hạn chế đơn hình.

Dưới đây là một số liên kết mà tôi thấy hữu ích và có thể giúp bạn hiểu hoặc đi sâu hơn vào chủ đề:

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.