#haskell #idris
#haskell #idris
Вопрос:
Я начал читать главу 6 «Разработка на основе типов с помощью Idris» и попытался написать интеллектуальный конструктор для кортежного вектора.
TupleVect : Nat -> Type -> Type
TupleVect Z _ = ()
TupleVect (S k) a = (a, TupleVect k a)
someValue : TupleVect 4 Nat
someValue = (1,2,3,4,())
TupleVectConstructorType : Nat -> Type -> Type
TupleVectConstructorType n typ = helper n
where
helper : Nat -> Type
helper Z = TupleVect n typ
helper (S k) = typ -> helper k
tupleVect : (n : Nat) -> (a : Type) -> TupleVectConstructorType n a
tupleVect Z a = ()
tupleVect (S Z) a = val => (val, ())
tupleVect (S (S Z)) a = val2 => val1 => (val2, val1, ())
-- ??? how to create tupleVect (S k) a
Как создать конструктор для произвольного k?
Ответ №1:
В основном идея @Matthias Berndt. Обратный отсчет стрелок, которые нужно добавить, делая конечный кортеж длиннее. Для этого нам нужно получить доступ к более разрешительному помощнику из TupleVectType
.
TupleVectType' : Nat -> Nat -> Type -> Type
TupleVectType' Z n a = TupleVect n a
TupleVectType' (S k) n a = a -> TupleVectType' k (S n) a
TupleVectType : Nat -> Type -> Type
TupleVectType n = TupleVectType' n Z
tupleVect : (n : Nat) -> (a : Type) -> TupleVectType n a
tupleVect n a = helper n Z a ()
where
helper : (k, n : Nat) -> (a : Type) -> (acc : TupleVect n a)
-> TupleVectType' k n a
helper Z n a acc = acc
helper (S k) n a acc = x => helper k (S n) a (x, acc)
someValue2 : TupleVect 4 Nat
someValue2 = (tupleVect 4 Nat) 4 3 2 1
Хотя обратите внимание, что это приведет к v2 => v1 => (v1, v2, ())
, а не v2 => v1 => (v2, v1, ())
к тому, что первое лучше соответствует рекурсивному определению TupleVect (S k) a = (a, TupleVect k a)
.
Комментарии:
1. Хорошее решение. Но это должно быть возможно упростить.
helper
a
параметр type не нужен, потому что вы можете просто использоватьa
из области видимости. То же самое касаетсяTupleVectType'
, который вы можете просто объявить вtupleVect
where
предложении ‘s. Тогда естьk
inhelper
. Если вы переименуетеn
переменную вtupleVect
tom
, тоk
это простоm - n
и, следовательно, избыточно. К сожалению, я просто не смог скомпилировать код после внесения этих изменений :-/2. @MatthiasBerndt
a
действительно избыточен.TupleVectType'
должно быть явным, чтобыhelper
можно было получить к нему доступ. Использованиеm - n
должно бытьminus m n
таким, чтобы вам не приходилось иметь дело сLTE
доказательством, но вам все равно пришлось бы иметь дело с другими доказательствами и некоторымиrewrite
s, так что вариант withk
просто проще вводить (в смысле клавиатуры и системы типов :-)), хотя и не является строго необходимым.
Ответ №2:
Я почти ничего не знаю об Idris, за исключением того, что это зависимый типизированный язык, подобный Haskell. Но я нахожу эту проблему интригующей, поэтому я попробовал.
Очевидно, что здесь вам нужно рекурсивное решение. Моя идея состоит в том, чтобы использовать дополнительный параметр f
, который накапливает val1
.. val_n
параметры, которые функция съела до сих пор. При достижении базового f
варианта возвращается.
tupleVectHelper Z a f = f
tupleVectHelper (S n) a f = val => tupleVectHelper n a (val, f)
tupleVect n a = tupleVectHelper n a ()
Я понятия не имею, работает ли это, и я еще не понял, как написать тип tupleVectHelper
, но я попытался выполнить замены вручную для n = 3
, и, похоже, это работает на бумаге, хотя результирующий кортеж задом наперед. Но я думаю, что это не должно быть слишком сложно исправить.
Надеюсь, это поможет!