从类型列表中获取常规列表

hel*_*elq 3 haskell types ghc dependent-type

我已经找到了将a Nat转换为Integer使用的方法Proxy,natVal您可以在下面的代码中看到:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Main where

import Data.Proxy (Proxy)
import Data.Monoid ((<>))
import GHC.TypeLits

main :: IO ()
main = do
  fromNat (undefined :: Proxy 5)

fromNat :: KnownNat n => Proxy n -> IO ()
fromNat proxy = do
  let (num :: Integer) = natVal proxy -- converting a Nat to an Integer
  putStrLn $ "Some num: " <> show num
Run Code Online (Sandbox Code Playgroud)

但是我无法想出将类型列表转换为常规列表的简单方法,下面的代码甚至不会键入check:

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Main where

import Data.Proxy (Proxy)
import Data.Monoid ((<>))
import GHC.TypeLits

main :: IO ()
main = do
  fromNat     (undefined :: Proxy 5)
  fromListNat (undefined :: Proxy '[2,3,10])

fromNat :: KnownNat n => Proxy n -> IO ()
fromNat proxy = do
  let (num :: Integer) = natVal proxy -- converting a Nat to an Integer
  putStrLn $ "Some num: " <> show num

fromListNat :: Proxy [Nat] -> IO ()
fromListNat = undefined
Run Code Online (Sandbox Code Playgroud)

如何将类型列表转换为常规列表?

Ale*_*lec 5

答案是为类似KnownNat级别列表制作类似的东西Nat.我们使用类型类在类型级别列表上进行归纳.这个类型类通过其超类约束,将检查列表中的所有元素是否满足KnownNat,然后它将使用该事实来重构术语级列表.

{-# LANGUAGE TypeOperators, KindSignatures #-}

-- Similar to `KnownNat (n :: Nat)`
class KnownNatList (ns :: [Nat]) where
   natListVal :: proxy ns -> [Integer]

-- Base case
instance KnownNatList '[] where
  natListVal _ = []

-- Inductive step
instance (KnownNat n, KnownNatList ns) => KnownNatList (n ': ns) where
  natListVal _ = natVal (Proxy :: Proxy n) : natListVal (Proxy :: Proxy ns)
Run Code Online (Sandbox Code Playgroud)

然后,fromListNat采取相同的形状fromNat:

fromListNat :: KnownNatList ns => Proxy ns -> IO ()
fromListNat proxy = do
  let (listNum :: [Integer]) = natListVal proxy
  putStrLn $ "Some list of num: " <> show listNum
Run Code Online (Sandbox Code Playgroud)

将这些更改拼接到您的初始代码中,我得到了预期的输出:

$ ghc Main.hs
$ ./Main
Some num: 5
Some list of num: [2,3,10]
Run Code Online (Sandbox Code Playgroud)