Fix và Mu đẳng cấu


8

Trong recursion-schemesgói các loại sau được định nghĩa:

newtype Fix f = Fix (f (Fix f))

newtype Mu f = Mu (forall a. (f a -> a) -> a)

Chúng có phải là đẳng cấu không? Nếu vậy, làm thế nào để bạn chứng minh điều đó?


3
Có liên quan: Sự khác biệt giữa gói Fix, Mu và Nu trong gói lược đồ đệ quy của Ed Kmett là gì (điều duy nhất câu trả lời không có là sự đẳng cấu được viết rõ ràng).
song công

Trong haskell có (vì lười biếng) trong ngôn ngữ nghiêm ngặt sẽ làMu f < Fix f < Nu f
xgrommx

2
@duplode Về các đẳng cấu; Fix-to- Muvề cơ bản cata, trong khi Mu-to- Fixmu2fix (Mu x) = x Fix. Phần khó khăn đang chứng minh rằng đây là những nghịch đảo lẫn nhau, khai thác tham số.
chi

Ngoài ra, bạn có thể giải quyết kata codewars.com/kata/folding- phiên
a -fixed

1
@xgrommx, trong một bối cảnh nghiêm ngặt, ví dụ về thuật ngữ có thể được đại diện bởi Fixcái gì không thể đại diện bởi Mu? ISTM Fixphải là nhỏ nhất (theo trực giác vì nó là "cấu trúc dữ liệu" và không thể chứa đáy)
luqui

Câu trả lời:


4

Chúng có phải là đẳng cấu không?

Vâng, chúng là đẳng cấu trong Haskell. Xem sự khác biệt giữa gói Fix, Mu và Nu trong gói chương trình đệ quy của Ed Kmett để biết thêm một số nhận xét.

Nếu vậy, làm thế nào để bạn chứng minh điều đó?

Hãy bắt đầu bằng cách xác định các chức năng để thực hiện chuyển đổi:

muToFix :: Mu f -> Fix f
muToFix (Mu s) = s Fix

fixToMu :: Functor f => Fix f -> Mu f
fixToMu t = Mu (\alg -> cata alg t)

Để hiển thị các hàm đó chứng kiến ​​một đẳng cấu, chúng ta phải chỉ ra rằng:

muToFix . fixToMu = id
fixToMu . muToFix = id

Từ Fixvà trở lại

Một trong những hướng của sự đẳng cấu đi ra có phần đơn giản hơn so với hướng khác:

muToFix (fixToMu t) = t
muToFix (fixToMu t)  -- LHS
muToFix (Mu (\f -> cata f t))
(\f -> cata f t) Fix
cata Fix t  -- See below.
t  -- LHS = RHS

Đoạn cuối cùng ở trên, cata Fix t = tcó thể được xác minh thông qua định nghĩa cata:

cata :: Functor f => (f a -> a) -> Fix f -> a
cata alg = alg . fmap (cata alg) . unfix

cata Fix t, sau đó, là Fix (fmap (cata Fix) (unfix t)). Chúng ta có thể sử dụng cảm ứng để chỉ ra nó t, ít nhất là đối với một hữu hạn t(nó trở nên tinh tế hơn với các cấu trúc vô hạn - xem phần phụ lục ở cuối câu trả lời này). Có hai khả năng để xem xét:

  • unfix t :: f (Fix f)trống rỗng, không có vị trí đệ quy để đào sâu vào. Trong trường hợp đó, nó phải bằng fmap absurd zvới một số z :: f Void, và do đó:

    cata Fix t
    Fix (fmap (cata Fix) (unfix t))
    Fix (fmap (cata Fix) (fmap absurd z))
    Fix (fmap (cata Fix . absurd) z)
    -- fmap doesn't do anything on an empty structure.
    Fix (fmap absurd z)
    Fix (unfix t)
    t
  • unfix tkhông có sản phẩm nào. Trong trường hợp đó, ít nhất chúng tôi biết rằng fmap (cata Fix)không thể làm gì ngoài việc áp dụng cata Fixcho các vị trí đệ quy. Giả thuyết cảm ứng ở đây là làm như vậy sẽ khiến những vị trí đó không thay đổi. Chúng tôi sau đó có:

    cata Fix t
    Fix (fmap (cata Fix) (unfix t))
    Fix (unfix t)  -- Induction hypothesis.
    t

(Cuối cùng, cata Fix = idlà một hệ quả tất yếu của Fix :: f (Fix f) -> Fix xviệc ban đầu F-đại số. Resorting trực tiếp đến thực tế rằng trong bối cảnh chứng minh điều này có lẽ sẽ là quá nhiều của một phím tắt.)

Từ Muvà trở lại

Đưa ra muToFix . fixToMu = id, để chứng minh rằng fixToMu . muToFix = idnó đủ để chứng minh:

  • đó muToFixlà tiêm, hoặc

  • đó fixToMulà tính từ.

Hãy chọn tùy chọn thứ hai và xem xét các định nghĩa liên quan:

newtype Mu f = Mu (forall a. (f a -> a) -> a)

fixToMu :: Functor f => Fix f -> Mu f
fixToMu t = Mu (\alg -> cata alg t)

fixToMusau đó là tính từ, có nghĩa là, với bất kỳ cụ thể nào Functor f, tất cả các chức năng của loại forall a. (f a -> a) -> acó thể được định nghĩa là \alg -> cata alg t, đối với một số cụ thể t :: Fix f. Sau đó, tác vụ sẽ trở thành mục lục các forall a. (f a -> a) -> achức năng và xem liệu tất cả chúng có thể được thể hiện dưới dạng đó hay không.

Làm thế nào chúng ta có thể định nghĩa một forall a. (f a -> a) -> achức năng mà không cần dựa vào fixToMu? Không có vấn đề gì, nó phải liên quan đến việc sử dụng f a -> ađại số được cung cấp làm đối số để có akết quả. Các tuyến đường trực tiếp sẽ được áp dụng nó cho một số f agiá trị. Một cảnh báo chính là, vì alà đa hình, chúng ta phải có khả năng gợi ra f agiá trị nói cho bất kỳ sự lựa chọn nào a. Đó là một chiến lược khả thi miễn là giá ftrị tồn tại. Trong trường hợp đó, chúng ta có thể làm:

fromEmpty :: Functor f => f Void -> forall a. (f a -> a) -> a
fromEmpty z = \alg -> alg (fmap absurd z)

Để làm cho ký hiệu rõ ràng hơn, hãy xác định một loại cho những thứ chúng ta có thể sử dụng để xác định các forall a. (f a -> a) -> ahàm:

data Moo f = Empty (f Void)

fromMoo :: Functor f => Moo f -> forall a. (f a -> a) -> a
fromMoo (Empty z) = \alg -> alg (fmap absurd z)

Bên cạnh tuyến đường trực tiếp, chỉ có một khả năng khác. Cho rằng đó flà một Functor, nếu bằng cách nào đó chúng ta có một f (Moo f)giá trị, chúng ta có thể áp dụng đại số hai lần, ứng dụng đầu tiên nằm dưới flớp ngoài , thông qua fmapfromMoo:

fromLayered :: Functor f => f (Moo f) -> forall a. (f a -> a) -> a
fromLayered u = \alg -> alg (fmap (\moo -> fromMoo moo alg) u)

Xem xét rằng chúng ta cũng có thể tạo forall a. (f a -> a) -> ara các f (Moo f)giá trị, thật hợp lý khi thêm chúng vào như một trường hợp Moo:

data Moo f = Empty (f Void) | Layered (f (Moo f))

Theo đó, fromLayeredcó thể được kết hợp để fromMoo:

fromMoo :: Functor f => Moo f -> forall a. (f a -> a) -> a
fromMoo = \case
    Empty z -> \alg -> alg (fmap absurd z)
    Layered u -> \alg -> alg (fmap (\moo -> fromMoo moo alg) u)

Lưu ý rằng, bằng cách làm như vậy, chúng tôi đã lén lút chuyển từ áp dụng algdưới một flớp sang áp dụng đệ quy algdưới một số flớp tùy ý .

Tiếp theo, chúng ta có thể lưu ý một f Voidgiá trị có thể được đưa vào hàm Layeredtạo:

emptyLayered :: Functor f => f Void -> Moo f
emptyLayered z = Layered (fmap absurd z)

Điều đó có nghĩa là chúng ta không thực sự cần nhà Emptyxây dựng:

newtype Moo f = Moo (f (Moo f))

unMoo :: Moo f -> f (Moo f)
unMoo (Moo u) = u

Còn Emptytrường hợp trong fromMoothì sao? Sự khác biệt duy nhất giữa hai trường hợp là, trong Emptytrường hợp, chúng ta có absurdthay vì \moo -> fromMoo moo alg. Vì tất cả các Void -> achức năng là absurd, chúng tôi không cần một Emptytrường hợp riêng ở đó:

fromMoo :: Functor f => Moo f -> forall a. (f a -> a) -> a
fromMoo (Moo u) = \alg -> alg (fmap (\moo -> fromMoo moo alg) u)

Một tinh chỉnh mỹ phẩm có thể là lật các fromMoođối số, do đó chúng ta không cần phải viết đối số thành fmaplambda:

foldMoo :: Functor f => (f a -> a) -> Moo f -> a
foldMoo alg (Moo u) = alg (fmap (foldMoo alg) u)

Hoặc, nhiều điểm hơn:

foldMoo :: Functor f => (f a -> a) -> Moo f -> a
foldMoo alg = alg . fmap (foldMoo alg) . unMoo

Tại thời điểm này, cái nhìn thứ hai về các định nghĩa của chúng tôi cho thấy một số đổi tên theo thứ tự:

newtype Fix f = Fix (f (Fix f))

unfix :: Fix f -> f (Fix f)
unfix (Fix u) = u

cata :: Functor f => (f a -> a) -> Fix f -> a
cata alg = alg . fmap (cata alg) . unfix

fromFix :: Functor f => Fix f -> forall a. (f a -> a) -> a
fromFix t = \alg -> cata alg t

Và đó là: tất cả các forall a. (f a -> a) -> achức năng có hình thức \alg -> cata alg tcho một số t :: Fix f. Do đó, fixToMulà tính từ, và chúng ta có sự đẳng cấu mong muốn.

Phụ lục

Trong các ý kiến, một câu hỏi phàm tục được đưa ra về khả năng áp dụng của đối số cảm ứng trong cata Fix t = tđạo hàm. Tối thiểu, luật functor và tham số đảm bảo rằng fmap (cata Fix)sẽ không tạo thêm công việc (ví dụ: nó sẽ không phóng to cấu trúc hoặc giới thiệu các vị trí đệ quy bổ sung để đào sâu vào), điều này chứng minh tại sao bước vào các vị trí đệ quy là tất cả các vấn đề trong bước quy nạp của đạo hàm. Điều đó là như vậy, nếu tlà một cấu trúc hữu hạn, trường hợp cơ bản của một sản phẩm trống f (Fix t)cuối cùng sẽ đạt được, và tất cả đều rõ ràng. tTuy nhiên, nếu chúng ta cho phép là vô hạn, chúng ta có thể tiếp tục giảm dần vô tận, fmapsau fmapđó fmap, mà không bao giờ đạt đến trường hợp cơ sở.

Tuy nhiên, tình huống với các cấu trúc vô hạn không phải là khủng khiếp như lúc đầu. Sự lười biếng, đó là điều làm cho các cấu trúc vô hạn trở nên khả thi ngay từ đầu, cho phép chúng ta tiêu thụ các cấu trúc vô hạn một cách lười biếng:

GHCi> :info ListF
data ListF a b = Nil | Cons a b
    -- etc.
GHCi> ones = Fix (Cons 1 ones)
GHCi> (\(Fix (Cons a _)) -> a) (cata Fix ones)
1
GHCi> (\(Fix (Cons _ (Fix (Cons a _)))) -> a) (cata Fix ones)
1

Mặc dù sự thành công của các vị trí đệ quy kéo dài vô tận, chúng ta có thể dừng lại ở bất kỳ điểm nào và nhận được kết quả hữu ích từ ListFbối cảnh functorial xung quanh . Các bối cảnh như vậy, nó lặp đi lặp lại, không bị ảnh hưởng fmap, và vì vậy bất kỳ phân đoạn hữu hạn nào của cấu trúc chúng ta có thể tiêu thụ sẽ không bị ảnh hưởng cata Fix.

Sự lười biếng này phản ánh làm thế nào, như đã đề cập ở nơi khác trong cuộc thảo luận này, sự lười biếng làm sụp đổ sự phân biệt giữa các điểm cố định Mu, FixNu. Không có sự lười biếng, Fixkhông đủ để mã hóa corecursion sản xuất, và vì vậy chúng tôi phải chuyển sang Nu, điểm cố định lớn nhất. Đây là một minh chứng nhỏ cho sự khác biệt:

GHCi> :set -XBangPatterns
GHCi> -- Like ListF, but strict in the recursive position.
GHCi> data SListF a b = SNil | SCons a !b deriving Functor
GHCi> ones = Nu (\() -> SCons 1 ()) ()
GHCi> (\(Nu c a) -> (\(SCons a _) -> a) (c a)) ones
1
GHCi> ones' = Fix (SCons 1 ones')
GHCi> (\(Fix (SCons a _)) -> a) ones'
^CInterrupted.

Làm thế nào để bạn biện minh cata Fix t = t? Giả sử Fix flà đại số ban đầu cho fcó vẻ như một chút của một phím tắt. (Bằng chứng được liên kết từ câu trả lời liên quan dường như bỏ qua điều này bằng cách sử dụng tham số cả hai cách.)
Li-yao Xia

Tôi không hiểu bằng chứng về fixToMutính siêu thực của nó. "nếu chúng ta muốn xác định một forall a. (fa -> a) -> một hàm từ đầu" Đó không phải là điều chúng ta muốn. Thay vào đó, hãy để k :: forall a. (f a -> a) -> a, chúng tôi cần thể hiện điều đó k = \alg -> cata alg tcho một số t.
Li-yao Xia

[1/2] @ Li-yaoXia (1) Bật cata Fix, chúng tôi có cata Fix = Fix . fmap (cata Fix) . unfix. Nếu tkhông có vị trí đệ quy, fmap (cata Fix)sẽ không làm gì cả, và như vậy cata Fix t = Fix (unfix t) = t. Nếu nó có vị trí đệ quy, tất cả fmap (cata Fix)sẽ làm là áp dụng cata Fixcho chúng, có vẻ đủ để giải quyết vấn đề bằng cảm ứng.
song công

[2/2] @ Li-yaoXia (2) Về tính siêu thực: Đối số là bất kỳ khả năng nào kcũng phải có được bằng cách áp dụng trực tiếp đại số (cần một f Voidgiá trị) hoặc bằng cách sử dụng fmapđể áp dụng đệ quy và cả hai trường hợp đều có thể được thể hiện dưới dạng \ alg -> cata alg t`. Vì vậy, tôi tin rằng tôi đã thực hiện những gì bạn đề xuất, mặc dù "từ đầu" có thể không phải là lựa chọn tốt nhất để diễn tả nó.
song công

1
@ Li-yaoXia Tôi đã điều chỉnh ngôn ngữ mô tả đối số tính từ và thêm cata Fix t = tđạo hàm (thực tế, với sự tương đồng giữa hai đối số, bây giờ tôi cảm thấy việc đặt ra nó giúp chuẩn bị nền tảng cho phần thứ hai của câu trả lời) . Cảm ơn đã làm nổi bật những điểm đó để cải thiện.
song mã
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.