簡體   English   中英

如何使Vect n Int成為Monoid的一個實例

[英]How to make Vect n Int an instance of Monoid

在Idris中, Vect na是表示包含類型a的項的n長度的向量的數據類型。 想象一下,我有一個功能:

foo : Int -> Vect 4 Int
foo n = [n-1, n, n+1, n*4]

函數的主體並不重要,它可以是返回4 Ints向量的任何東西。 現在,我想將此函數與concatMap一起使用,如下所示:

bar : Vect n Int -> Vect (4*n) Int
bar vals = concatMap foo vals

Bar是一個函數,它采用長度為n的Int向量並返回長度為4 * n的向量。

concatMap的類型簽名是:

Prelude.Foldable.concatMap : Foldable t => Monoid m => (a -> m) -> t a -> m

因此,如果我嘗試編譯bar,我會收到錯誤:

 When elaborating right hand side of bar:
     Can't resolve type class Monoid (Vect (plus n (plus n (plus n (plus n 0)))) Int)

這意味着Vect n Int不是monoid的實例。 為了使它成為monoid的一個實例,我需要實現:

Prelude.Algebra.neutral : Monoid a => a

不幸的是,我不知道該怎么做。 List實現了monoid,如下所示:

instance Monoid (List a) where
    neutral = []

但是,如果我嘗試使用中性= []為Vect n Int實現monoid,我收到錯誤:

 When elaborating right hand side of Prelude.Algebra.Vect n Int instance of Prelude.Algebra.Monoid, method neutral:
 |   Can't unify
 |           Vect 0 Int
 |   with
 |           Vect n Int
 |   
 |   Specifically:
 |           Can't unify
 |                   0
 |           with
 |                   n

所以我想知道,我將如何為Vect實現monoid?

你不能實現一個monoid,這樣你就可以使用concatMap寫下該表達式。 想想concatMap的簽名:

(Foldable t, Monoid m) => (a -> m) -> t a -> m

請注意, m在函數參數的返回類型(a -> m)和整個函數的返回類型中必須是相同的Monoid 然而, 這不是 Vect na 的情況 考慮一下表達式:

concatMap foo vals

這里foo將有一個類型a -> Vect 4 a ,你想要的concatMap的結果是Vect (4*n) a ,其中n是原始向量的長度。 但是這不適合concatMap類型,因為你有一個concatMap的應用程序需要類似的類型:

(Foldable t, Monoid m, Monoid m1) => (a -> m) -> t a -> m1

其中結果monoid和函數返回的值可以是不同的類型,而concatMap強制使用相同的類型。

[a]Vect na是完全不同的,因為[] 包括在類型的長度,並且這允許編寫一個concatMap功能。 實際上,這允許您為[]創建Monoid實例,並將其連接為二元運算符。

當你開始將長度附加到一個類型時,這種可能性消失了,因為你不能再混合不同的長度,因此Vect na 不會形成用於連接的monoid。 在一般情況下,連接運算符變為類型a -> b -> c ,特別是它的類型為Vect s是Vect na -> Vect ma -> Vect (n+m) a ,這明顯不同於它的類型對於列表: [a] -> [a] ->[a]


這就是說,你報告的錯誤是由於這樣的事實,當為Monoid類的Vect na編寫一個實例時, neutral值必須是Vect na類型,但[]Vect 0 a類型。

但是,您可以通過Vect naMonoid類型類創建不同的實例。 如果這樣的矢量的元素是幺半群,那么你可以創建這種矢量的幺半群。

在這種情況下,他的neutral向量必須是長度為n ,並且你可以給它的元素唯一合理的值是元素Monoidneutral 基本上你想要將Vect naneutral replicate n neutral

然后, Monoid的二元運算將是元素之間操作的元素應用。

所以實例看起來像:

instance Monoid a => Monoid (Vect n a) where
    neutral = replicate n neutral

instance Semigroup a => Semigroup (Vect n a) where
    Nil <+> Nil = Nil
    (x :: xs) <+> (y :: ys) = (x <+> y) :: (xs <+> ys)

不幸的是,我不是Idris用戶/程序員,因此我無法准確地告訴您如何正確編寫此類代碼。 以上只是一個類似Haskell的偽代碼來概括這些概念。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM