Tôi đang cố gắng chứng minh tính kết hợp của các danh sách cấp độ theo cách cho phép tôi chuyển đổi giữa các loại tương đương mà không mang theo bất kỳ ràng buộc nào.
Giả sử định nghĩa chuẩn của phép nối:
type family (++) (xs :: [k]) (ys :: [k]) :: [k] where
'[] ++ ys = ys
(x ': xs) ++ ys = x ': (xs ++ ys)
Giả sử, tôi được cung cấp một chức năng:
given :: forall k (a :: [k]) (b :: [k]) (c :: [k]). Proxy ((a ++ b) ++ c)
given = Proxy -- Proxy is just an example
và tôi muốn gọi hàm này và sau đó sử dụng tính kết hợp:
my :: forall k (a :: [k]) (b :: [k]) (c :: [k]). Proxy (a ++ (b ++ c))
my = given @k @a @b @c -- Couldn't match type ‘(a ++ b) ++ c’ with ‘a ++ (b ++ c)’
Loại bình đẳng này thực sự không tầm thường, vì vậy không có gì ngạc nhiên khi trình biên dịch không hiểu nó, tuy nhiên tôi có thể chứng minh điều đó! Thật không may, tôi không biết làm thế nào để thuyết phục trình biên dịch mà tôi có thể.
Suy nghĩ đầu tiên tự nhiên của tôi là làm một cái gì đó như:
proof :: forall k (a :: [k]) (b :: [k]) (c :: [k]). (a ++ (b ++ c)) :~: ((a ++ b) ++ c)
proof = _
và sau đó thay đổi chức năng của tôi thành:
my :: forall k (a :: [k]) (b :: [k]) (c :: [k]). Proxy (a ++ (b ++ c))
my = case proof @k @a @b @c of Refl -> given @k @a @b @c
Nhưng tôi vẫn phải xác định proof
và đối với điều này, tôi cần thực hiện cảm ứng trên các đối số kiểu của nó. Cách duy nhất để thực hiện cảm ứng đối với các loại trong Haskell mà tôi biết là xác định một loại loại, nhưng sau đó tôi sẽ phải thêm các ràng buộc tương ứng cho loại my
mà tôi không muốn làm - thực tế là nó gọi given
và ép buộc kết quả là một chi tiết triển khai trên YouTube.
Có cách nào để chứng minh loại bình đẳng này trong Haskell mà không dùng đến các định đề không an toàn không?
(a++(b++c)) :~: ((a++b)++c)
mà không cần thêm các đối số đơn lẻ hoặc các ràng buộc kiểu chữ.