haskell - 使用泛型编程获取一个值中的所有 TypeRep
问题描述
有没有办法TypeRep
使用泛型编程获取一个值内所有 ' 的列表?
例如,是否可以定义一个函数:
typeReps :: (Data a, Typeable a) => a -> [TypeRep]
以这样的方式:
>>> typeReps (1 :: Int, 'a')
[(Int, Char), Int, Char]
>>> typeReps (Foo ['a', 'b'])
[Foo, [Char], Char, Char]
我试过了
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE RankNTypes #-}
module Example where
import Data.Data
import Data.Typeable
typeReps :: (Data a, Typeable a) => a -> TypeReps a
typeReps a = gfoldl step fcstr a
where
step :: forall d b. (Typeable d, Data d) => TypeReps (d -> b) -> d -> TypeReps b
step tot d = tot <++> typeReps d
fcstr :: forall g . g -> TypeReps g
fcstr g = TypeReps [typeOf a]
但是,这似乎与TypeRep
结果中的 type 重复:
>>> typeReps ['a']
TypeReps {getTypes = [[Char],Char,[Char]]}
此外,我没有使用g
但a
在fsctr
上面的函数中看起来有点倒退(我不能,因为我不能限制g
为Typeable
)。
我不知道这种方式能不能解决,如果不能,我想知道是否有其他方法可以接近它。
解决方案
正如评论中所建议的那样,您似乎没有考虑到[1,2,3]
实际情况1 : 2 : 3 : []
(每个尾部子项都有 type [Int]
)。您可以为列表添加一个特殊情况:
{-# LANGUAGE ViewPatterns #-}
import Data.Data
-- | Returns 'Just' only for lists
--
-- This can surely be done more efficiently, but it does the job.
listTypeReps :: Data a => a -> Maybe [TypeRep]
listTypeReps x
| typeRepTyCon (typeOf x) == listTyCon
, toConstr x == toConstr ([] :: [()]) -- empty list
= Just []
| typeRepTyCon (typeOf x) == listTyCon
, toConstr x == toConstr [()] -- cons
, [headTs, _] <- gmapQ typeReps x
, [_, Just tailTs] <- gmapQ listTypeReps x
= Just (headTs ++ tailTs)
| otherwise
= Nothing
listTyCon :: TyCon
listTyCon = typeRepTyCon (typeOf ([] :: [()]))
-- | Get the types of subterms
typeReps :: Data a => a -> [TypeRep]
typeReps x = typeOf x : case listTypeReps x of
Just ts -> ts
Nothing -> concat (gmapQ typeReps x)
试试看:
ghci> :set -XDeriveDataTypeable
ghci> data Foo = Foo [Int] (Char,Char) deriving (Data,Typeable)
ghci> typeReps $ Foo [1, 2] ('a', 'b')
[Foo,[Int],Int,Int,(Char,Char),Char,Char]
推荐阅读
- laravel - 无法在后台使用 Laravel-snappy 生成 pdf
- python - Tkinter 输入未插入数据库(sqlite3)
- javascript - 如何按升序对 JavaScript 中的嵌套数组进行排序?
- angular - 在 PrimeNG p-table 中单击取消按钮后如何保留复选框的选择?
- android - 在 Visual Studio 中构建 cordova android apk 时出错
- python - 调用 QScreen.grabWindow() 时输入错误
- c# - 如何安装 Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms?
- c - C中的名称排序
- delphi - Delphi 10.3.3 中的当前项目没有可用的平台
- react-hooks - useEffect 导致无限循环