迭代类型级别列表并根据列表中的每种类型调用函数

问题描述 投票:0回答:2

给定类型列表

{-# LANGUAGE DataKinds #-}

type MyTypes = '[String, Int, Char]

以及类似于以下的类型类:

class MyClass a where
  describe :: Proxy a -> String

instance MyClass String where
  describe _ = "a String is a String"

instance MyClass Int where
  describe _ = "an Int represents a number"

instance MyClass Char where
  describe _ = "a Char represents a single character"

如何迭代

MyTypes
并在列表中的每种类型上调用
describe
(假设列表中的每种类型都有
MyClass
的实例)?

我想我想要像

fmap
traverse
这样的东西在类型级别和值级别之间建立一座桥梁。
对于上面的类型列表,我想要的结果是
["a String is a String", "an Int represents a number", "a Char represents a single character"]

haskell types
2个回答
0
投票

sop-core包提供了有用的函数来处理类型级列表和由它们构造或索引的值。特别是 Data.SOP.NP

 模块专注于 n 元乘积(认为不同大小的元组,每个组件都包装在函子中)。

import Data.SOP ( K(..) ) import Data.SOP.NP ( NP, collapse_NP, cpure_NP )
首先,我们使用 

cpure_NP

 来获得齐次(因为由常数函子 K
 参数化)包含 
describe
 值的 n 元乘积:

descriptions :: NP (K String) MyTypes descriptions = cpure_NP (Proxy @MyClass) d where -- The type signature here is to be able to refer to `a` in the Proxy. -- Because we are using a constant functor, we don't really have an `a` value, -- only a String. d :: forall a. MyClass a => K String a d = K (describe (Proxy @a))

c-

中的
cpure_NP
是一种符号约定。它的意思是“函数假设
某个约束对于类型级列表的所有元素都成立,并且我们通过Proxy
提供该约束”。

因为产品是同质的,所以我们可以使用

collapse_NP

 将其转换为普通列表:

descriptionList :: [String] descriptionList = collapse_NP descriptions
    

0
投票
尝试在类型级别模拟高阶函数可能非常复杂。一个更特别的答案是创建一个类来映射带有

describe

 的列表。

import Data.Kind (Type) class MapMyClass (as :: [Type]) where mapDescribe :: Proxy as -> [String] instance MapMyClass '[] where mapDescribe _ = [] instance (MyClass a, MapMyClass as) => MapMyClass (a ': as) where mapDescribe as = describe (headProxy as) : mapDescribe (tailProxy as) headProxy :: Proxy (a ': as) -> Proxy a headProxy _ = Proxy tailProxy :: Proxy (a ': as) -> Proxy as tailProxy _ = Proxy
    
© www.soinside.com 2019 - 2024. All rights reserved.