我正在尝试在Haskell中嵌入预先计算的数据。那是
catToMap li = Map.fromList $ zip [0..] li
cat1 = catToMap ["aa", "bb", "cc"]
dim = Map.size cat1
我想在类型定义中静态使用dim
:
type Network = Grenade.Network
'[Grenade.FullyConnected dim 20, Grenade.FullyConnected 20 1, Grenade.Logit]
'[Grenade.D1 dim, Grenade.D1 20, Grenade.D1 1, Grenade.D1 1]
(从grenade
库导入)
但是,上面给出了dim
不在范围内的错误。
我也在尝试创建函数
import qualified Numeric.LinearAlgebra.Static as SA
-- | ith standard basis in Rn
stdbasis :: forall n . KnownNat n => Int -> SA.R n
stdbasis i = SA.vector [builder x| x <- [0..n-1]]
where
builder j = if i == j then 1 else 0
但是这给了我n
不在范围内的错误。
我解决第一个问题的尝试是使用模板Haskell:
catToMap = $(\li -> Map.fromList $ zip [0..] li)
cat1 = $(catToMap ["aa", "bb", "cc"])
dim = $(Map.size cat1)
但它给了我错误
• Couldn't match expected type ‘Q Exp’
with actual type ‘[a0] -> Map.Map Integer a0’
• The lambda expression ‘\ li -> (Map.fromList $ zip ... li)’
has one argument,
but its type ‘Language.Haskell.TH.Lib.ExpQ’ has none
In the expression: \ li -> (Map.fromList $ zip [0 .. ] li)
In the untyped splice: $(\ li -> (Map.fromList $ zip [0 .. ] li))
我想要实现的是类似于C ++模板:
template <int size> Vector<n>
stdbasis(int i);
答案 0 :(得分:1)
模板Haskell是正确的方法,但是您需要在正确的位置使用合适的TH构造函数来使用它。当场就是您要使用依赖于值级别计算的类型级别数量的地方。 dim
仍然是值级别的,但是Grenade.FullyConnected
的参数是类型级别的,因此您需要进行拼接。
这是一个完整的(简化的)示例:
module Dimension where -- No TH here, we just need a separate module
-- to put the value-level code whose results
-- are to be spliced into the type level
import Data.Map as Map
dim :: Integer
dim = fromIntegral $ Map.size cat1
where catToMap li = Map.fromList $ zip [0..] li
cat1 = catToMap ["aa", "bb", "cc"]
{-# LANGUAGE TemplateHaskell, TypeOperators, DataKinds #-}
module Main where
import Data.Modular
import Dimension
import Language.Haskell.TH
type F = ℤ / $(pure . LitT $ NumTyLit dim) -- this is where you'd define your Network type
main :: IO ()
main = print [0::F ..]
[0,1,2]