我的目标是编写带有一些多态值的函数,并列出表示具体类型的typereps。它返回具有相同值的新列表,但已经转换为通过typereps指定的具体类型。
我们有这样的值列表:启用["one", "two"]
的{{1}}
每个的类型分别为-XOverloadedStrings
。
我们可以通过这种方式获得的类型代码列表:
IsString a => a
有没有办法获得类型为import Data.Typeable (Proxy(..), typeRep)
import Data.Text (Text)
[typeRep (Proxy :: Proxy String), typeRep (Proxy :: Proxy ByteString)]
的{{1}}和"one"
类型的String
?
P.S。为了根据包含不同类型值的列表来防止错误,我们可以将"two"
中的每个值换行,如下例所示(伪代码):
ByteString
可以使用Template Haskell完成,但它太难看了。
答案 0 :(得分:5)
我无法想象你的目的,但代码可能看起来像这样。我正在使用新的Type.Reflection
界面,因为我对它比对经典Data.Typeable
更熟悉,但这也适用于此。
import Type.Reflection
types :: [SomeTypeRep]
types = [SomeTypeRep (typeRep @String), SomeTypeRep (typeRep @Text)]
strings :: [String]
strings = ["one", "two"]
converted :: [Dynamic]
converted = fromJust $ zipWithM convert types strings
convert :: SomeTypeRep -> String -> Maybe Dynamic
convert (SomeTypeRep rep) s
| Just HRefl <- eqTypeRep rep (typeRep @String) = Just $ toDynamic s
| Just HRefl <- eqTypeRep rep (typeRep @Text) = Just $ toDynamic (fromString s)
| otherwise = Nothing
答案 1 :(得分:3)
拿着我的啤酒。
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE OverloadedStrings #-}
import Data.ByteString (ByteString)
import Data.String
import Data.Text (Text)
data Forall c where Forall :: (forall a. c a => a) -> Forall c
data Exists c where Exists :: c a => a -> Exists c
data Evidence c where Evidence :: c a => proxy a -> Evidence c
instance c ~ IsString => IsString (Forall c) where
fromString s = Forall (fromString s)
asProxyType :: proxy a -> a -> a
asProxyType = const id
downcast :: Evidence c -> Forall c -> Exists c
downcast (Evidence proxy) (Forall v) = Exists (asProxyType proxy v)
polymorphicStrings :: c ~ IsString => [Forall c]
polymorphicStrings = ["one", "two"]
types :: c ~ IsString => [Evidence c]
types = [Evidence ([] :: [ByteString]), Evidence ([] :: [Text])]
monomorphicStrings :: c ~ IsString => [Exists c]
monomorphicStrings = zipWith downcast types polymorphicStrings
要连接问题:Exists Typeable
与Dynamic
同构。您可能需要将Forall, Exists :: Constraint -> *
概括为Forall, Exists :: [Constraint] -> *
,以便同时轻松支持IsString
和Typeable
,这有点类型级别的黑客攻击,但没有太费劲。类型系列可以为您提供Elem :: Constraint -> [Constraint] -> Bool
,可用于替换上面的c ~ IsString
。