我使用V
中的linear
处理此形状的数据类型:
type Foo n = V (n * 3) Double -> Double
将其修复为n
非常重要,因为我希望能够确保在编译时传递正确数量的元素。这是我的计划的一部分,已经运作良好,独立于我在这里做的事情。
对于任何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
传递给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
但是...... bar
和mkFoo
需要KnownNat (n * 3)
,但reflectNat
只是给了我KnownNat n
。
有什么方法可以概括reflectNat
让我满足foo
的证明吗?
答案 0 :(得分:3)
我发布了另一个答案,因为它更直接,编辑之前的胜利没有意义。
实际上使用诀窍(如果不是Edward Kmett发明的那样推广),来自reflections parent::__construct
:
reifyNat
所以当你运行它时:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
import GHC.TypeLits
import Data.Proxy
import Unsafe.Coerce
newtype MagicNat3 r = MagicNat3 (forall (n :: Nat). KnownNat (n * 3) => Proxy n -> r)
trickValue :: Integer -> Integer
trickValue = (*3)
-- No type-level garantee that the function will be called with (n * 3)
-- you have to believe us
trick :: forall a n. KnownNat n => Proxy n -> (forall m. KnownNat (m * 3) => Proxy m -> a) -> a
trick p f = unsafeCoerce (MagicNat3 f :: MagicNat3 a) (trickValue (natVal p)) Proxy
test :: forall m. KnownNat (m * 3) => Proxy m -> Integer
test _ = natVal (Proxy :: Proxy (m * 3))
诀窍是基于这样一个事实:在GHC中,一个成员类词典(如λ *Main > :t trick (Proxy :: Proxy 4) test :: Integer
trick (Proxy :: Proxy 4) test :: Integer :: Integer
λ *Main > trick (Proxy :: Proxy 4) test :: Integer
12
)由成员本身表示。在KnownNat
情况下,结果是KnownNat
。所以我们只在那里Integer
。通用量化使其从外部发出声音。
答案 1 :(得分:0)
你的问题不是很具描述性,所以我会尽量让自己感觉空白:
我们假设var textvalue = parseInt($('#ty' + (i + 1).toString()).text)
if (textvalue < 0) {
$('#ty' + (i + 1).toString()).addClass("fa-level-down");
$('#ty' + (i + 1).toString()).removeClass("fa-level-up");
}
else {
$('#ty' + (i + 1).toString()).addClass("fa-level-up");
$('#ty' + (i + 1).toString()).removeClass("fa-level-down");
}
是Blah n
。
我还假设Proxy n
是一种使用术语级自然数来调用普遍量化(超过类型reflectNat
)函数的方法。
我不会比编写自己的Nat
提供更好的方法
reflectNat
或者,使用{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
import GHC.TypeLits
import Data.Proxy
data Vec a (n :: Nat) where
Nil :: Vec a 0
Cons :: a -> Vec a n -> Vec a (1 + n)
vecToList :: Vec a n -> [a]
vecToList Nil = []
vecToList (Cons h t) = h : vecToList t
repl :: forall n a. KnownNat n => Proxy n -> a -> Vec a n
repl p x = undefined -- this is a bit tricky with Nat from GHC.TypeLits, but possible
foo :: forall (n :: Nat). KnownNat (1 + n) => Proxy n -> Vec Bool (1 + n)
foo _ = repl (Proxy :: Proxy (1 + n)) True
-- Here we have to write our own version of 'reflectNat' providing right 'KnownNat' instances
-- so we can call `foo`
reflectNat :: Integer -> (forall n. KnownNat (1 + n) => Proxy (n :: Nat) -> a) -> a
reflectNat = undefined
test :: [Bool]
test = reflectNat 5 $ \p -> vecToList (foo p)
即可使用singletons
。然后类型将是不同的
SomeSing
即。而不是魔法字典reflectNat :: Integer -> (forall (n :: Nat). SomeSing (n :: Nat) -> a) -> a
你有单独的具体价值。因此,在KnownNat
中,您需要明确地构建foo
,给定SomeSing (1 + n)
- 这非常简单。
在运行时,SomeSing n
字典和KnownNat
值将传递给数字值,并且在这种情况下显式是恕我直言.p)