是否有可能在伊德里斯中抽象出来?

时间:2018-01-21 21:04:28

标签: idris

我正在使用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,它似乎允许这里需要什么。我是否正确地认为这是伊德里斯为此而失踪的原因?或者在伊德里斯还有其他方法吗?

1 个答案:

答案 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