如何通过'TypeRep'指定值的类型?
How to specify type of value via 'TypeRep'?
我的目标是编写函数,该函数采用一些多态值并列出表示具体类型的类型。它 returns 具有相同值但已转换为通过 typereps 指定的具体类型的新列表。
让我们有这样的值列表:["one", "two"]
启用 -XOverloadedStrings
。
每一个的类型分别是IsString a => a
。
我们可以通过这种方式获得的 typereps 列表:
import Data.Typeable (Proxy(..), typeRep)
import Data.Text (Text)
[typeRep (Proxy :: Proxy String), typeRep (Proxy :: Proxy ByteString)]
有什么方法可以得到 String
类型的 "one"
和 ByteString
类型的 "two"
吗?
P.S。为了防止根据包含不同类型值的列表出错,我们可以将每个值都包装在 Dynamic.
中,如下例(伪代码):
{-# LANGUAGE ParallelListComp #-}
import Data.Dynamic (toDyn)
[ toDyn (val :: type') | val <- vals | type' <- concreteTypes ]
可以使用模板Haskell,但是太丑了。
拿着我的啤酒。
{-# 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
。
我真的无法想象你的目的,但代码可能看起来像这样。我正在使用新的 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
我的目标是编写函数,该函数采用一些多态值并列出表示具体类型的类型。它 returns 具有相同值但已转换为通过 typereps 指定的具体类型的新列表。
让我们有这样的值列表:["one", "two"]
启用 -XOverloadedStrings
。
每一个的类型分别是IsString a => a
。
我们可以通过这种方式获得的 typereps 列表:
import Data.Typeable (Proxy(..), typeRep)
import Data.Text (Text)
[typeRep (Proxy :: Proxy String), typeRep (Proxy :: Proxy ByteString)]
有什么方法可以得到 String
类型的 "one"
和 ByteString
类型的 "two"
吗?
P.S。为了防止根据包含不同类型值的列表出错,我们可以将每个值都包装在 Dynamic.
中,如下例(伪代码):
{-# LANGUAGE ParallelListComp #-}
import Data.Dynamic (toDyn)
[ toDyn (val :: type') | val <- vals | type' <- concreteTypes ]
可以使用模板Haskell,但是太丑了。
拿着我的啤酒。
{-# 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
。
我真的无法想象你的目的,但代码可能看起来像这样。我正在使用新的 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