[英]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 na
為Monoid
類型類創建不同的實例。 如果這樣的矢量的元素是幺半群,那么你可以創建這種矢量的幺半群。
在這種情況下,他的neutral
向量必須是長度為n
,並且你可以給它的元素唯一合理的值是元素Monoid
的neutral
。 基本上你想要將Vect na
的neutral
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.