我正在处理这种形状的数据类型,使用V
from linear
:
type Foo n = V (n * 3) Double -> Double
将其固定在n
非常重要,因为我希望能够确保在编译时传递正确数量的元素。这是我的程序的一部分,已经运行良好,独立于我在这里所做的事情。
For any KnownNat n
,我可以生成一个Foo n
满足我的程序所需的行为。就这个问题而言,这可能是一些愚蠢的事情,比如
mkFoo :: KnownNat (n * 3) => Foo n
mkFoo = sum
或者对于一个更有意义的例子,它可以生成一个随机的V
相同长度和用途dot
就两者而言。这KnownNat
这里的约束是多余的,但实际上,需要做一个Foo
。我做了一个Foo
并将其用于我的整个程序(或多个输入),所以这保证了我每当我使用它时,我都会在具有相同长度的东西上使用,并且在结构相同的东西上使用Foo
规定。
最后,我有一个函数可以为Foo
:
bar :: KnownNat (n * 3) => Proxy n -> [V (n * 3) Double]
bar这实际上是我使用的原因n * 3
作为类型函数,而不是仅仅手动扩展它。原因是bar
可以通过使用三个长度向量来完成它的工作n
并将它们作为长度向量附加在一起n * 3
。还,n
从语义上来说,对于函数来说是一个更有意义的参数n * 3
。这也让我禁止不正确的价值观,例如n
不是 3 的倍数,等等。
现在,之前,只要我在开始时定义了一个类型同义词,一切都可以正常工作:
type N = 5
然后我就可以进去Proxy :: Proxy N
to bar
,并使用mkFoo :: Foo N
。一切都很好。
-- works fine
doStuff :: [Double]
doStuff = let inps = bar (Proxy :: Proxy N)
in map (mkFoo :: Foo N) inps
但现在我希望能够调整N
在运行时通过从文件或命令行参数加载信息。
我尝试通过打电话来做到这一点reflectNat
:
doStuff :: Integer -> Double
doStuff n = reflectNat 5 $ \pn@(Proxy :: Proxy n) ->
let inps = bar (Proxy :: Proxy n)
in map (mkFoo :: Foo n) inps
But...bar
and mkFoo
要求KnownNat (n * 3)
, but reflectNat
只是给我KnownNat n
.
有什么方法可以概括证明reflectNat
让我满足foo
?