在Haskell中编译时间常量

时间:2018-06-17 14:38:48

标签: haskell template-haskell

我正在尝试在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);

1 个答案:

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