В Идрисе Vect n a
представляет собой тип данных, представляющий вектор n длины, содержащий элементы типа a. Представьте себе, у меня есть функция:Как сделать Vect n Int экземпляром Monoid
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 это функция, которая принимает вектор Int длины п и возвращает единица длиной 4 * п.
Тип подписи concatMap является:
Prelude.Foldable.concatMap : Foldable t => Monoid m => (a -> m) -> t a -> m
И поэтому, если я пытаюсь скомпилировать бар, я получаю ошибку:
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 п Int не является экземпляром моноидом. Чтобы сделать это экземпляр моноиде, мне нужно реализовать:
Prelude.Algebra.neutral : Monoid a => a
Однако, к сожалению, я не знаю, как это сделать. Список реализует моноид, следующим образом:
instance Monoid (List a) where
neutral = []
Но если я пытаюсь реализовать моноид с нейтральным = [] для Vect п Int, я получаю сообщение об ошибке:
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?
Конкатенация влияет на длину вектора, поэтому 'Vect n a' не может быть моноидом, так как в результате значение' n' должно быть удвоено. Вам нужен пользовательский 'concat: Vect n (Vect ma) -> Vect (n * m) a', который, вероятно, нуждается в' _ ++ _: Vect na -> Vect ma -> Vect (n + m) a' и некоторые арифметические леммы, такие как 'n * m + m = (succ n) * m'. – chi
@chi В stdlib idris есть функция '' concat' '(http://www.idris-lang.org/docs/prelude_doc/docs/Prelude.Vect.html#Prelude.Vect.concat). – Bakuriu