Haskell 如何映射参数?
给定类型Haskell 如何映射参数?,haskell,generics,Haskell,Generics,给定类型X=X Int,我想定义一个函数toX::[String]->X,它在运行时使用泛型构造X 当我这样写下来时,这很容易: toX :: [String] -> X toX (x:[y]) = to (M1 (M1 (M1 (K1 $ read x) :*: (M1 (K1 $ read y))))) toX xs = to (M1 (M1 (toX' xs))) toX' (x:[]) = M1 (K1 x) toX' (x:xs) = M1 (K1 x) :*: (toX'
X=X Int
,我想定义一个函数toX::[String]->X
,它在运行时使用泛型构造X
当我这样写下来时,这很容易:
toX :: [String] -> X
toX (x:[y]) = to (M1 (M1 (M1 (K1 $ read x) :*: (M1 (K1 $ read y)))))
toX xs = to (M1 (M1 (toX' xs)))
toX' (x:[]) = M1 (K1 x)
toX' (x:xs) = M1 (K1 x) :*: (toX' xs)
但我不知道如何递归(如果我们有两个以上的参数)。我的第一次尝试是这样的:
toX :: [String] -> X
toX (x:[y]) = to (M1 (M1 (M1 (K1 $ read x) :*: (M1 (K1 $ read y)))))
toX xs = to (M1 (M1 (toX' xs)))
toX' (x:[]) = M1 (K1 x)
toX' (x:xs) = M1 (K1 x) :*: (toX' xs)
它(当然)会失败,并出现类型错误。查看(:*:)
的类型更让我困惑:(:*:)::fp->gp->(:*:)fp
。我完全不知道这种类型应该是什么意思,以及如何从这里开始。
有什么提示吗
#!/usr/bin/env stack
{- stack --resolver lts-8.4 runghc-}
{-# LANGUAGE DeriveGeneric #-}
import GHC.Generics
data X = X Int Int deriving (Generic, Show)
main :: IO ()
main = do
print $ toXeasy ["2","4"]
-- print $ toX ["2","4"]
toXeasy :: [String] -> X
toXeasy (x:[y]) = to (M1 (M1 (M1 (K1 $ read x) :*: (M1 (K1 $ read y)))))
--toX :: [String] -> X
--toX xs = to (M1 (M1 (toX' xs)))
--toX' (x:[]) = M1 (K1 x)
--toX' (x:xs) = M1 (K1 x) :*: (toX' xs)
这定义了一个函数
readFields::[String]->对于任何Generic
数据类型X
,它只有一个构造函数(至少有一个字段)
readFields
是使用泛型版本gReadFields
定义的,它与泛型表示(即,使用出现在GHC.Generics
中的类型构造函数构造的类型:M1
,(:*:)
,K1
…)
定义读取单个字段的操作。重要的是要有一个实例Applicative(StateT[String]可能)
,这样才能组合它
-- Takes a string from the state and reads it out.
readM :: Read a => StateT [String] Maybe a
readM = StateT readM'
where
readM' (x : xs) | Just a <- readMaybe x = Just (a, xs)
readM' _ = Nothing
这定义了一个函数readFields::[String]->对于任何Generic
数据类型X
,它只有一个构造函数(至少有一个字段)
readFields
是使用泛型版本gReadFields
定义的,它与泛型表示(即,使用出现在GHC.Generics
中的类型构造函数构造的类型:M1
,(:*:)
,K1
…)
定义读取单个字段的操作。重要的是要有一个实例Applicative(StateT[String]可能)
,这样才能组合它
-- Takes a string from the state and reads it out.
readM :: Read a => StateT [String] Maybe a
readM = StateT readM'
where
readM' (x : xs) | Just a <- readMaybe x = Just (a, xs)
readM' _ = Nothing
以下是一个使用以下方法的解决方案:
以下是一个使用以下方法的解决方案:
下面是您可能需要思考的问题-应该是什么类型的toX'
?它甚至有一个类型吗?On需要有更多的类型级别信息才能做到这一点。一个HList
就足够了。不清楚为什么要使用泛型来实现这一点。使用泛型定义函数应该包括定义类型类。我猜你有多种类型,都是简单的值记录,对吗?你能通过展示你想要处理的各种类型的例子和简单的单元测试来澄清你的问题吗?@李耀霞目前我只是想看看泛型有什么可能。我正在尝试重新实现类似于cassava/csv管道(将csv解析为数据类型)的东西,但这只是一个用于学习目的的最小示例。我在问题中提出了代码,并认为使用递归定义会更优雅。@AlectoX'
的类型对我来说是个谜,因为:*:
的类型对我来说是个谜:)不确定HList
在这里会有什么帮助,这几天你会想一想的。以下是你可能想思考的问题:toX'
的类型应该是什么?它甚至有一个类型吗?On需要有更多的类型级别信息才能做到这一点。一个HList
就足够了。不清楚为什么要使用泛型来实现这一点。使用泛型定义函数应该包括定义类型类。我猜你有多种类型,都是简单的值记录,对吗?你能通过展示你想要处理的各种类型的例子和简单的单元测试来澄清你的问题吗?@李耀霞目前我只是想看看泛型有什么可能。我正在尝试重新实现类似于cassava/csv管道(将csv解析为数据类型)的东西,但这只是一个用于学习目的的最小示例。我在问题中提出了代码,并认为使用递归定义会更优雅。@AlectoX'
的类型对我来说是个谜,因为:*:
的类型对我来说是个谜:)不确定HList
在这里会有什么帮助,这些天会考虑它。所有这些都会阅读部分函数!我希望看到更像gReadFields::MaybeT(State[String])(fp)
的东西。好吧,我希望现在看起来更好!谢谢没有泛型的版本,非常有趣!你可能想看看我最近的一段关于one liner
的文章。所有这些都是阅读
部分函数!我希望看到更像gReadFields::MaybeT(State[String])(fp)
的东西。好吧,我希望现在看起来更好!谢谢没有泛型的版本,非常有趣!你可能想看看我最近的一段关于one liner
。
readFields xs = evalStateT (createA (For :: For Read) readM) xs
main = print (readFields ["14", "42"] :: Maybe (Int, Int))
{-# LANGUAGE DataKinds, TypeFamilies, FlexibleContexts, TypeApplications #-}
{-# LANGUAGE TemplateHaskell #-}
module ReadFields where
import Data.Maybe
import Generics.SOP
import Generics.SOP.TH
readFields ::
(Generic a, Code a ~ '[ xs ], All Read xs) => [String] -> Maybe a
readFields xs =
to . SOP . Z . hcmap (Proxy @Read) (I . read . unK) <$> fromList xs
data X = X Int Int
deriving Show
deriveGeneric ''X
GHCi> readFields @X ["3", "4"]
Just (X 3 4)
GHCi> readFields @X ["3"]
Nothing