Tại sao functor Haskell chỉ có các loại dẫn xuất trong thể loại mục tiêu của họ?


12

Trong Haskell, functor kiểu chữ Functor được định nghĩa như sau (xem ví dụ: Haskell wiki ):

class Functor (f :: * -> *) where
  fmap :: (a -> b) -> f a -> f b 

Theo như tôi hiểu (hãy sửa lại cho tôi nếu tôi sai), một functor như vậy chỉ có thể có mục đích một loại xây dựng bằng một constructor loại, ví dụ như [], Maybevv Mặt khác, người ta có thể nghĩ về functors có bất kỳ loại là mục tiêu của functor, ví dụ như danh mục của tất cả các loại Haskell. Ví dụ, Intcó thể là một đối tượng trong danh mục đích của functor, không chỉ Maybe Inthoặc [Int].

Động lực cho sự hạn chế này đối với functor Haskell là gì?


4
Sự đơn giản? Haskell không có các hàm loại hạng nhất, vì vậy tất cả các hàm thực sự chỉ là các hàm tạo.
Daniel Gratzer

2
@jozefg: Xin tha thứ cho sự thiếu hiểu biết của tôi: "các hàm loại hạng nhất" là gì?
Giorgio

4
Vì vậy, trong chức năng đó, chúng ta đang xoay quanh một fquyền? Và trong kịch bản của bạn, fnên giống như một hàm Haskell bình thường và các kiểu ánh xạ thành các loại. Trong Haskell, những thứ duy nhất được phép có loại * -> *là các hàm tạo kiểu. Những gia đình kiểu thường chung chung hơn, nhưng họ phải luôn được áp dụng đầy đủ
Daniel Gratzer


@jozefg: Thỉnh thoảng tôi nghĩ về câu hỏi này nhiều lần. Tôi cho rằng hạn chế Haskell không ảnh hưởng đến sức mạnh biểu cảm của functor. Ví dụ: giả sử rằng chúng ta có một functor đồng hình với danh sách functor, nhưng không ánh xạ, giả sử, Int -> [Int] nhưng Int -> <kiểu lạ mắt không sử dụng hàm tạo kiểu>. Sau đó, tôi đoán người ta có thể chứng minh rằng <kiểu ưa thích không sử dụng hàm tạo kiểu> là đẳng cấu với [Int]. Vì vậy, việc chọn các đối tượng được xác định bằng cách sử dụng hàm tạo kiểu chỉ thuận tiện và không làm mất đi sức mạnh biểu cảm.
Giorgio

Câu trả lời:


1

Không có giới hạn nào cả! Khi tôi bắt đầu học cơ sở lý thuyết thể loại cho các nhà xây dựng kiểu, chính điểm này cũng làm tôi bối rối. Chúng ta sẽ đến đó. Nhưng trước tiên, hãy để tôi làm sáng tỏ một số nhầm lẫn. Hai trích dẫn:

một functor như vậy chỉ có thể có một thể loại mục tiêu một thể loại được xây dựng bằng cách sử dụng một hàm tạo

người ta có thể nghĩ rằng functor có bất kỳ thể loại nào là mục tiêu của functor, ví dụ như thể loại của tất cả các loại Haskell

cho thấy rằng bạn đang hiểu nhầm một functor là gì (hoặc ít nhất, bạn đang sử dụng thuật ngữ sai).

Functor không xây dựng thể loại. Một functor là một ánh xạ giữa các thể loại. Functor mang các đối tượng và hình thái (loại và chức năng) trong thể loại nguồn cho đối tượng và hình thái trong thể loại mục tiêu.

Lưu ý rằng điều này có nghĩa là một functor thực sự là một cặp ánh xạ: ánh xạ trên các đối tượng F_obj và ánh xạ trên các hình thái F_morph . Trong Haskell, phần đối tượng F_obj của functor là tên của hàm tạo kiểu (ví dụ List), trong khi phần hình thái là hàm fmap(tùy thuộc vào trình biên dịch Haskell để sắp xếp mà fmapchúng ta đang đề cập đến trong bất kỳ biểu thức đã cho nào). Vì vậy, chúng ta không thể nói rằng đó Listlà một functor; chỉ có sự kết hợp của Listfmaplà một functor. Tuy nhiên, mọi người lạm dụng ký hiệu; các lập trình viên gọi Listmột functor, trong khi các nhà lý thuyết thể loại sử dụng cùng một biểu tượng để chỉ cả hai phần của functor.

Hơn nữa, trong lập trình, hầu hết tất cả các functor đều là endofunctor , nghĩa là, loại nguồn và mục tiêu là như nhau - loại của tất cả các loại trong ngôn ngữ của chúng tôi. Hãy gọi thể loại này Loại . Một endofunctor F trên Type ánh xạ một loại T sang loại FT khác và một chức năng T -> S sang một chức năng khác FT -> FS . Bản đồ này tất nhiên phải tuân theo luật functor.

Sử dụng Listnhư một ví dụ: chúng ta có một hàm tạo kiểu List : Type -> Typevà một hàm fmap: (a -> b) -> (List a -> List b), cùng nhau tạo thành một functor. T

Có một điểm cuối cùng để làm sáng tỏ. Viết List intkhông tạo ra một loại danh sách số nguyên mới. Loại này đã tồn tại . Đó là một đối tượng trong nhóm của chúng tôi Loại . List Intchỉ đơn giản là một cách để tham khảo nó.

Bây giờ, bạn đang tự hỏi tại sao một functor không thể ánh xạ một loại, nói, Inthoặc String. Nhưng nó có thể! Người ta chỉ phải sử dụng functor danh tính. Đối với bất kỳ loại C nào , functor danh tính ánh xạ mọi đối tượng vào chính nó và hình thái cho chính nó. Thật đơn giản để xác minh ánh xạ này thỏa mãn các luật functor. Trong Haskell, đây sẽ là một hàm tạo kiểu id : * -> *ánh xạ mọi kiểu tới chính nó. Ví dụ, id intđánh giá để int.

Hơn nữa, người ta thậm chí có thể tạo functor không đổi , ánh xạ tất cả các loại thành một loại duy nhất. Ví dụ, functor ToInt : * -> *, nơi ToInt a = intdành cho tất cả các loại avà ánh xạ tất cả các hình thái vào hàm nhận dạng số nguyên: fmap f = \x -> x


Cảm ơn câu trả lời của bạn, câu hỏi này đã hơn hai tuổi. "Functor không xây dựng danh mục.": Tôi không nói như vậy. Tôi đã nói rằng functors bản đồ hai loại, nơi mà các loại mục tiêu phải có hình thức f a, nơi flà, theo như tôi biết, một constructor loại. Từ những gì tôi nhớ từ lý thuyết thể loại, đây phải là một dạng biểu diễn chính tắc (đối tượng ban đầu trong một danh mục? Có lẽ tôi đang sử dụng thuật ngữ này.) Dù sao, tôi sẽ đọc kỹ câu trả lời của bạn. Cảm ơn nhiều.
Giorgio

@Giorgio rất tiếc, tôi không nhận ra nó bao nhiêu tuổi haha. Nó chỉ xuất hiện trong "những câu hỏi chưa được trả lời". Tôi không chắc ý của bạn là "đại diện chính tắc". Theo như tôi biết (và tôi có thể sai ở đây), không có mối quan hệ nào giữa functor và các đối tượng ban đầu / đầu cuối.
vườn

Ý tôi là thế này: vi.wikipedia.org/wiki/Initial_acheebra (xem Sử dụng trong khoa học máy tính). Trong hàm functor của Haskell (hầu hết) được xác định trên các kiểu dữ liệu đại số. Đối tượng mục tiêu của functor như vậy là một đại số ban đầu. Đại số ban đầu là đẳng cấu với tập hợp các thuật ngữ được xây dựng bằng cách sử dụng các hàm tạo giá trị. Ví dụ, cho danh sách, []:. Tôi có nghĩa là điều này bằng đại diện kinh điển.
Giorgio

Vâng, tôi biết đối tượng ban đầu là gì và các kiểu dữ liệu quy nạp là các đối tượng ban đầu trong đại số F của một thể loại. Bạn đã đúng rằng nhiều hàm tạo kiểu được định nghĩa theo quy nạp. Nhưng điều này không thực sự cần thiết. Ví dụ, các functor (_, int)mà phải mất một loại ađể loại sản phẩm (a, int)và chức năng f : 'a -> 'bđể g : 'a * int -> 'a * intkhông quy nạp.
vườn

Ý bạn là: "mất ... một chức năng f : 'a -> 'bđể g : 'a * int -> 'b * int?
Giorgio
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.