当前位置: 首页 > 知识库问答 >
问题:

如何为向量类型强制长度2^n定义可用的应用实例

谷梁镜
2023-03-14

对于某些应用程序,我需要长度为$2^n$的向量。为了确保某些操作的长度匹配,我使用ist应用程序实例定义了我的类型,如下所示:

{-# LANGUAGE GADTs, DataKinds, FlexibleInstances, FlexibleContexts #-}
data Nat = Z | N Nat
data Vector n t where
  S :: t -> Vector Z t
  V :: Vector n t -> Vector n t -> Vector (N n) t

instance Functor (Vector n) where
  fmap f (S t ) = S (f t)
  fmap f (V t t') = V (fmap f t) (fmap f t')

instance Applicative (Vector Z) where
  pure = S
  S f <*> S a = S (f a)

instance Applicative (Vector n) => Applicative (Vector (N n)) where
  pure a = let a' = pure a in V a' a'
  V f f' <*> V a a' = V (f <*> a) (f' <*> a')

我选择了ghci建议的语言扩展来编译代码。整个结构的灵感来自于如何使固定长度的向量成为Applicative?的实例?。

当我试图使用它时,麻烦就开始了:

instance Num t => Num (Vector n t) where
  v + v' = (+) <$> v <*> v'
  (*) = undefined
  abs = undefined
  signum = undefined
  fromInteger = undefined
  negate = undefined

添加这些行会触发以下错误:

无法推断(适用(向量n))由使用'

•在表达式中:()v

我正在Windows 7上使用Haskell Platform 8.0.2-a。

知道是怎么回事吗?在相关的问题中,同样的技巧似乎奏效了!?(在第一行添加KindSignature没有帮助,如果没有Flexible实例/上下文,我会得到一个编译器错误。)

共有2个答案

益智明
2023-03-14

我认为使用辅助类更好一点。我也倾向于liftA2而不是

class App' n where
  pure' :: a -> Vector n a

instance App' 'Z where
  pure' = S

instance App' n => App' ('N n) where
  pure' a = let a' = pure' a in V a' a'

liftA2'
  :: (a -> b -> c)
  -> Vector n a
  -> Vector n b
  -> Vector n c
liftA2' f = \xs -> go xs
  where
    go (S x) (S y) = S (f x y)
    go (V l1 r1) (V l2 r2) =
      V (go l1 l2) (go r1 r2)

instance App' n => Applicative (Vector n) where
  pure = pure'
  -- import Control.Applicative to get the liftA2 method
  liftA2 = liftA2'

董嘉祯
2023-03-14

您应该在您的Num(Vector n t)实例声明中添加一个类型约束,指定Vector n aApplative的实例,否则您不能使用

因此,您可以通过以下方式解决问题:

instance (Num t, Applicative (Vector n)) => Num (Vector n t) where
  v + v' = (+) <$> v <*> v'
  -- ...

因此,我们在这里说,Vector n tNum的一个实例,给定的tNum的一个实例,Vector nApplicative的一个实例

由于您为您的Vector n定义了应用程序实例,因此它适用于所有Vector ns,因此所有Vector n ts都是给定Num t的成员,而不管n的值,但它需要是实例声明的签名的一部分。

 类似资料:
  • 我创建了一个示例容器,它在内部存储在std::vector中。我希望能够用std::vector初始化容器。因此,我创建了一个构造函数,它采用std::initializer_list,还采用begin和end。 但我似乎不能这样初始化: 这里的问题是什么?我该怎么修复? 代码在这里:

  • 问题内容: 我有一个形状为(12,)的numpy数组。我想重塑它,使[[1,2,3,4,5,6,7,8,9,10,11,12]]变为 我尝试了a.reshape(3,4)和a.reshape(-1,4),但是没有任何东西可以产生我想要的东西。有没有一种简单的方法可以做到这一点,还是我需要创建一个新数组并分别设置每个值? 问题答案: 重塑形状以将第一个轴分成两个,后者的长度和转置- 或按以下顺序重塑

  • 我在Kotlin中有一个方法,它返回一个泛型列表的Rx可观察值: 因为Kotlin list特征定义为,Java将看到返回类型为。 是否有一种方法告诉Kotlin编译器,Java应该将其视为?

  • 问题内容: 我想将非spring bean类对象用作球衣Web服务类方法的参数。但是它在构建时会给出缺少的依赖项错误。 我的代码是: 问题答案: 关键是路径参数以字符串形式出现。根据规范,如果我们希望将自定义类型作为注入,则自定义类应具有以下三项之一: 返回类型的公共静态 返回类型的公共静态 或接受字符串的公共构造函数 另一种选择实现。您可以在此处查看示例。 如果您不拥有该类(它是无法更改的第三方

  • 问题内容: 如果一个类定义了一个注释,是否有可能迫使其子类定义相同的注释? 例如,我们有一个简单的类/子类对,它们共享 我想做的事情,就是迫使每个进一步的子类定义相同的注释,以防止将来出现问题。 TestClass.java: TestSubClass.java: 我知道我可以在运行时枚举所有批注并检查是否丢失了,但是我真的很想在编译时执行此操作(如果可能)。 问题答案: 您可以在编译时使用JSR

  • 问题内容: 我想使用泛型类型来确保方法的参数具有相同的类型,如下所示: 我假设传递给此方法的两个参数(a和b)始终必须具有相同的类型。但是令我惊讶的是,无论传递了什么参数,我都能将任何类型的参数(甚至是基本参数)传递给方法x,就好像T被抹去了Object一样。 到目前为止,我发现的唯一解决方法是使用“ extends”,如下所示: 但是,尽管我可以忍受,但这并不是我想要的。 有没有一种方法可以使用