Haskell 从字符串读取并转换为动态
我想实现如下功能:Haskell 从字符串读取并转换为动态,haskell,Haskell,我想实现如下功能: readToDyn::String->Maybe Dynamic readToDyn x = readMaybe x >>= pure . toDyn 它将字符串转换为特定类型,然后将其打包为动态类型。问题是readMaybe::Read a=>String->Maybe a中的类型变量a不明确,因此无法编译 在上面定义函数时,有没有办法忽略这种不明确的情况,以便我可以在调用fromDynamic时指定类型?像 动态是一种存在类型。这意味着,每个包装的值实
readToDyn::String->Maybe Dynamic
readToDyn x = readMaybe x >>= pure . toDyn
它将字符串转换为特定类型,然后将其打包为动态类型。问题是readMaybe::Read a=>String->Maybe a中的类型变量a不明确,因此无法编译
在上面定义函数时,有没有办法忽略这种不明确的情况,以便我可以在调用fromDynamic时指定类型?像
动态是一种存在类型。这意味着,每个包装的值实际上属于一个具体的“静态类型”,在检查它之前,您不知道是哪个
data Dynamic where
Dynamic :: ∀ a. TypeRep a -> a -> Dynamic
-- i.e. ∀ a.(TypeRep a -> a -> Dynamic)
这使用了一个适用于所有人的quantor,但可以说,用一个在Haskell中目前不合法的存在主义quantor来理解它会更好:
data Dynamic where
Dynamic :: (∃ a. (TypeRep a, a)) -> Dynamic
请注意,quantor现在位于构造函数的参数中,而之前它位于整个构造函数中
您想要的是一种通用类型,即基础值本身不知道它将是什么类型,但可以适应调用站点所需的任何类型。这用参数中的通用量词表示:
data AnyReadable where
AnyReadable :: (∀ a. Read a => a) -> AnyReadable
但是,这对于读取并不起作用,至少对于字符串->可能是AnyReadable不起作用,因为在确定是否存在解析错误之前,您需要知道要读取它的类型
动态是一种存在类型。这意味着,每个包装的值实际上属于一个具体的“静态类型”,在检查它之前,您不知道是哪个
data Dynamic where
Dynamic :: ∀ a. TypeRep a -> a -> Dynamic
-- i.e. ∀ a.(TypeRep a -> a -> Dynamic)
这使用了一个适用于所有人的quantor,但可以说,用一个在Haskell中目前不合法的存在主义quantor来理解它会更好:
data Dynamic where
Dynamic :: (∃ a. (TypeRep a, a)) -> Dynamic
请注意,quantor现在位于构造函数的参数中,而之前它位于整个构造函数中
您想要的是一种通用类型,即基础值本身不知道它将是什么类型,但可以适应调用站点所需的任何类型。这用参数中的通用量词表示:
data AnyReadable where
AnyReadable :: (∀ a. Read a => a) -> AnyReadable
但是,这对读取不起作用,至少对String->AnyReadable不起作用,因为在确定是否存在解析错误之前,您需要知道要读取的类型。简单的解决方案是只存储字符串,然后再解析它 在构建动态值时,如果不知道稍后使用fromDynamic时将需要哪种类型,则无法解析字符串。在此阶段无法执行任何有用的预处理 原则上,您可以使用通用限定类型,例如:
data Parsed = Parsed { parse :: forall a . Read a => Maybe a }
readToDyn :: String -> Dynamic
readToDyn x = toDyn (Parsed (readMaybe x))
-- ...
do let x = readToDyn someString
-- ...
use (parse (fromDynamic x) :: Maybe Int)
但这毫无意义地复杂。注意readToDyn不返回Maybe Dynamic,因为这里没有办法知道以后解析是否会失败,这反映出我们不知道需要解析Int。简单的解决方案是只存储字符串,然后再解析它 在构建动态值时,如果不知道稍后使用fromDynamic时将需要哪种类型,则无法解析字符串。在此阶段无法执行任何有用的预处理 原则上,您可以使用通用限定类型,例如:
data Parsed = Parsed { parse :: forall a . Read a => Maybe a }
readToDyn :: String -> Dynamic
readToDyn x = toDyn (Parsed (readMaybe x))
-- ...
do let x = readToDyn someString
-- ...
use (parse (fromDynamic x) :: Maybe Int)
但这毫无意义地复杂。注意readToDyn不会返回Maybe Dynamic,因为这里无法知道解析是否会在以后失败,这反映出我们不知道我们将需要解析Int。您的问题的另一种解释是:您想从字符串中确定要使用的具体类型。即readToDyn 4应给出一个整数,readToDyn True应给出一个布尔值,等等。。这样的方法总是不完整的,但是如果您只需要它来处理有限的类型集合,那么这是可以的。基本上,你会这样做:
{-# LANGUAGE TypeApplications #-}
import Control.Applicative ((<|>))
readToDyn :: String -> Maybe Dynamic
readToDyn s = (toDyn @Integer <$> readMaybe s)
<|> (toDyn @Bool <$> readMaybe s)
<|> ...
更优雅/可扩展的方法:
{-# LANGUAGE TypeApplications, DataKinds, TypeInType
, AllowAmbiguousTypes, UnicodeSyntax, ScopedTypeVariables #-}
import Data.Kind (Type)
class DynRead (ts :: [Type]) where
readToDyn :: String -> Maybe Dynamic
instance DynRead ('[]) where
readToDyn _ = Nothing
instance ∀ h t . (Read h, Typeable h, DynRead t) => DynRead (h ': t) where
readToDyn s = toDyn @h <$> readMaybe s
<|> readToDyn @t s
对您的问题的另一种解释是:您想从字符串中确定要使用的具体类型。即readToDyn 4应给出一个整数,readToDyn True应给出一个布尔值,等等。。这样的方法总是不完整的,但是如果您只需要它来处理有限的类型集合,那么这是可以的。基本上,你会这样做:
{-# LANGUAGE TypeApplications #-}
import Control.Applicative ((<|>))
readToDyn :: String -> Maybe Dynamic
readToDyn s = (toDyn @Integer <$> readMaybe s)
<|> (toDyn @Bool <$> readMaybe s)
<|> ...
更优雅/可扩展的方法:
{-# LANGUAGE TypeApplications, DataKinds, TypeInType
, AllowAmbiguousTypes, UnicodeSyntax, ScopedTypeVariables #-}
import Data.Kind (Type)
class DynRead (ts :: [Type]) where
readToDyn :: String -> Maybe Dynamic
instance DynRead ('[]) where
readToDyn _ = Nothing
instance ∀ h t . (Read h, Typeable h, DynRead t) => DynRead (h ': t) where
readToDyn s = toDyn @h <$> readMaybe s
<|> readToDyn @t s