我正在使用Idris进行类型驱动开发,了解如何使用可变数量的参数定义函数。我有点野心勃勃,希望编写一个mapN
函数,将(n : Nat)
参数的函数映射到某些n
类型的Applicative
值。
调查这个问题导致我认为,如果没有至少也提供函数的参数类型,那可能是不可能的。这导致我尝试编写一个函数,该函数将采用Nat
和可变数量的Type
参数,并返回一个函数类型,就像您在类型之间串起箭头一样。如:
Arrows 0 Int = Int
Arrows 1 Int String = Int -> String
这是我最好的尝试,但不起作用:
Arrows : (n : Nat) -> (a : Type) -> Type
Arrows Z a = a
Arrows (S k) a = f where
f : Type -> Type
f b = Arrows k a -> b
不幸的是,类型签名都没有意义,因为有时候我希望函数返回Type
,有时会返回Type -> Type
,有时会返回Type -> Type -> Type
等等。我认为这与使用可变数量的参数编写任何其他函数大致相同,但似乎因为这些参数是类型,所以可能是不可能的。
寻找答案,我遇到了Haskell中-XPolyKinds启用的Kind Polymorphism,它似乎允许这里需要什么。我是否正确地认为这是伊德里斯为此而失踪的原因?或者在伊德里斯还有其他方法吗?
答案 0 :(得分:2)
好吧,Arrows
有一个依赖类型,正如您所说:
Arrows 0 : Type -> Type
Arrows 1 : Type -> Type -> Type
Arrows 2 : Type -> Type -> Type -> Type
请注意,此处Type
的外观不会改变任何内容。具体而言,请注意Type : Type
,(Type -> Type) : Type
等。它可能是Int
。它可能是n ** Vect n (Fin n)
。换句话说,类型和种类之间没有区别。
所以:
arrowsTy : Nat -> Type
arrowsTy Z = Type
arrowsTy (S k) = Type -> arrowTy k
可用于定义Arrows
的类型。
然后您可以定义Arrows
:
Arrows : (n : Nat) -> Type -> arrowTy n
Arrows Z a = a
Arrows (S k) a = compose (\b => a -> b) . Arrows k
where compose : { n : Nat } -> (Type -> Type) -> arrowsTy n -> arrowsTy n
-- compose is used to modify the eventual result of the recursion
compose { n = Z } g f = g f
compose { n = S k } g f = compose g . f
并且,如果您将compose
合并到Arrows
,则可以获得另一个版本:
Arrows' : (Type -> Type) -> (n : Nat) -> Type -> arrowTy n
Arrows' finalize Z x = finalize x
Arrows' finalize (S k) x = Arrows' (finalize . (\r => x -> r)) k
Arrows : (n : Nat) -> Type -> arrowTy n
Arrows = Arrows' id