Tôi đang thử nghiệm với các loại depedent trong Haskell và đi qua sau trong paper của 'độc thân' gói:Làm thế nào để mổ xẻ một SNAT (độc thân)
replicate2 :: forall n a. SingI n => a -> Vec a n
replicate2 a = case (sing :: Sing n) of
SZero -> VNil
SSucc _ -> VCons a (replicate2 a)
Vì vậy, tôi đã cố gắng để thực hiện điều này bản thân mình, chỉ cần toget một cảm giác như thế nào nó hoạt động:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Singletons
import Data.Singletons.Prelude
import Data.Singletons.TypeLits
data V :: Nat -> * -> * where
Nil :: V 0 a
(:>) :: a -> V n a -> V (n :+ 1) a
infixr 5 :>
replicateV :: SingI n => a -> V n a
replicateV = replicateV' sing
where replicateV' :: Sing n -> a -> V n a
replicateV' sn a = case sn of
SNat -> undefined -- what can I do with this?
Bây giờ vấn đề là các Sing
dụ cho Nat
không có SZero
hoặc SSucc
. Chỉ có một hàm tạo được gọi là SNat
.
> :info Sing
data instance Sing n where
SNat :: KnownNat n => Sing n
này khác với độc thân khác mà cho phép kết hợp, chẳng hạn như STrue
và SFalse
, chẳng hạn như trong những điều sau đây (vô dụng) ví dụ:
data Foo :: Bool -> * -> * where
T :: a -> Foo True a
F :: a -> Foo False a
foo :: forall a b. SingI b => a -> Foo b a
foo a = case (sing :: Sing b) of
STrue -> T a
SFalse -> F a
Bạn có thể sử dụng fromSing
để có được một loại cơ sở, nhưng điều này tất nhiên không cho phép GHC kiểm tra loại vector đầu ra:
-- does not typecheck
replicateV2 :: SingI n => a -> V n a
replicateV2 = replicateV' sing
where replicateV' :: Sing n -> a -> V n a
replicateV' sn a = case fromSing sn of
0 -> Nil
n -> a :> replicateV2 a
Vì vậy, câu hỏi của tôi: cách triển khai replicateV
?
EDIT
Câu trả lời được đưa ra bởi erisco giải thích lý do tại sao cách tiếp cận của tôi về giải cấu trúc một SNat
không hoạt động. Nhưng ngay cả với thư viện type-natural
, tôi không thể triển khai replicateV
cho loại dữ liệu V
bằng cách sử dụng GHC tích hợp Nat
loại.
Ví dụ đoạn mã sau biên dịch:
replicateV :: SingI n => a -> V n a
replicateV = replicateV' sing
where replicateV' :: Sing n -> a -> V n a
replicateV' sn a = case TN.sToPeano sn of
TN.SZ -> undefined
(TN.SS sn') -> undefined
Nhưng điều này dường như không cung cấp đủ thông tin để trình biên dịch để suy ra dù n
là 0
hay không. Ví dụ sau đây đưa ra một lỗi biên dịch:
replicateV :: SingI n => a -> V n a
replicateV = replicateV' sing
where replicateV' :: Sing n -> a -> V n a
replicateV' sn a = case TN.sToPeano sn of
TN.SZ -> Nil
(TN.SS sn') -> undefined
này cung cấp cho các lỗi sau:
src/Vec.hs:25:28: error:
• Could not deduce: n1 ~ 0
from the context: TN.ToPeano n1 ~ 'TN.Z
bound by a pattern with constructor:
TN.SZ :: forall (z0 :: TN.Nat). z0 ~ 'TN.Z => Sing z0,
in a case alternative
at src/Vec.hs:25:13-17
‘n1’ is a rigid type variable bound by
the type signature for:
replicateV' :: forall (n1 :: Nat) a1. Sing n1 -> a1 -> V n1 a1
at src/Vec.hs:23:24
Expected type: V n1 a1
Actual type: V 0 a1
• In the expression: Nil
In a case alternative: TN.SZ -> Nil
In the expression:
case TN.sToPeano sn of {
TN.SZ -> Nil
(TN.SS sn') -> undefined }
• Relevant bindings include
sn :: Sing n1 (bound at src/Vec.hs:24:21)
replicateV' :: Sing n1 -> a1 -> V n1 a1 (bound at src/Vec.hs:24:9)
Vì vậy, vấn đề ban đầu của tôi vẫn còn, tôi vẫn không thể làm bất cứ điều gì hữu ích với SNat
.
Điều này mang lại mọi thứ tôi ghét về kiểu 'Nat' được tích hợp sẵn của GHC. Không thể chứng minh những thứ như '(n + 1) - 1 ~ n', cũng như sự lúng túng xung quanh kiểm tra nếu' n ~ 0'. 'replicateV2' là một phép toán đệ quy cơ bản mà bạn cần cảm ứng qua chiều dài vectơ. Không có một định nghĩa quy nạp cho 'Nat' bạn đi đâu cả. Hãy để tôi làm điều này rõ ràng: bất kỳ giải pháp cho vấn đề của bạn sẽ _have_ để sử dụng cái gì đó bỏ qua hệ thống kiểu (hoặc thông qua một plugin hoặc 'unsafeCoerce'). Mặt khác, bạn có thể làm mọi thứ một cách an toàn và dễ dàng với 'dữ liệu Nat = Z | S Nat'. – Alec
Đây là những gì tôi đã bắt đầu lo sợ, rằng thực sự không có giải pháp cho vấn đề này. Tuy nhiên, tôi đã hy vọng có một số cách giải quyết phổ biến mà tôi không biết. Tôi sẽ chờ đợi cho đến khi tiền thưởng là hơn hy vọng cho một phép lạ. Nhưng nếu không, sau đó tôi đoán bình luận của bạn trả lời câu hỏi của tôi, và tôi sẽ sử dụng 'unsafeCoerce'. –
Lý do tôi rất quan tâm đến việc sử dụng 'Nat' được tích hợp sẵn là một số thư viện mà tôi đang sử dụng cũng sử dụng các kiểu' Nat' có sẵn. Đặc biệt là 'Numeric.LinearAlgebra.Static' từ' hmatrix'. Tôi liên tục gặp phải các vấn đề với chứng minh liên quan đến 'Nat' khi cố gắng ngay cả những thứ đơn giản nhất như lặp lại các hàng ma trận, v.v. –