我有一个如下所示的数据类型:
data MyAwesomeType = MyAwesomeType {
a :: String,
b :: String,
c :: String,
...
-- 25 in total
} deriving (Show)
我有一些看起来像这样的数据:
let xs = [["A", "B", "C", ...],["D", "E", "F", ...]]
为类型中的每个字段添加一个值。
如何将自定义数据类型应用于上面列表中的每个元素?我试图做这样的事情,这不起作用:
map (MyAwesomeType) xs
答案 0 :(得分:6)
您需要定义一个函数,以便从给定类型转换为自定义类型。在上面的示例中,您需要一个函数
myAwesomeTypeConverter :: [String] -> Maybe MyAwesomeType
myAwesomeTypeConverter (a:b:c:[]) = Just $ MyAwesomeType a b c
myAwesomeTypeConverter _ = Nothing
现在您可以使用此功能映射数组
map myAwesomeTypeConverter xs
答案 1 :(得分:4)
您可以使用 lambda表达式:
map (\[a,b,c] -> MyAwesomeType a b c) xs
然而,我们通常不太喜欢使用这样的列表:在编译时,未知列表中有多少元素,因此如果少于或多于3,则会出错。如果您想要一些通用结构来存储值。
你最好使用元组(这里是(String,String,String)
,因为现在你知道有三个元素,而且元素可以有不同的类型(列表不是这种情况):
let xs = [("A", "B", "C"),("D", "E", "F")]
-- ^ tuple ^ ^ tuple ^
然后你可以使用:
map (\(a,b,c) -> MyAwesomeType a b c) xs
如果“参数”的数量很大(即25),那么当然这不会非常优雅。在这种情况下,您可以决定使用模板Haskell ,例如:
module Templates where
import Control.Monad(replicateM)
import Language.Haskell.TH.Syntax(newName,Pat(ListP,VarP),Exp(LamE,VarE,AppE))
listmap n = do
xs <- replicateM n $ newName "x"
f <- newName "f"
return $ LamE [VarP f,ListP (map VarP xs)] $ foldl AppE (VarE f) $ map VarE xs
现在在您的主程序中,您可以使用$(listmap 25)
:
*Template> :t $(listmap 25)
$(listmap 25)
:: (t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t1
-> t)
-> [t1] -> t
因此,这构造了一个函数,该函数将t1
上的25 t
映射为一个函数,然后构造一个将t1
列表映射到{{1 }}
然后您可以像:
一样使用它t
如前所述,你最好使用元组,你可以用:
import Templates(listmap)
{-# LANGUAGE TemplateHaskell #-}
map ($(listmap 25) MyAwesomeType) xs
然后可以使用,例如:
module Templates where
import Control.Monad(replicateM)
import Language.Haskell.TH.Syntax(newName,Pat(TupP,VarP),Exp(LamE,VarE,AppE))
curryN n = do
xs <- replicateM n $ newName "x"
f <- newName "f"
return $ LamE [VarP f,TupP (map VarP xs)] $ foldl AppE (VarE f) $ map VarE xs
答案 2 :(得分:3)
另一种方法,使用generics-sop:
{-# language DeriveGeneric #-}
{-# language TypeOperators #-}
{-# language TypeFamilies #-}
{-# language DataKinds #-}
{-# language FlexibleContexts #-}
{-# language ScopedTypeVariables #-}
import qualified GHC.Generics as GHC
import Generics.SOP
data MyAwesomeType = MyAwesomeType
{
a :: String,
b :: String,
c :: String
} deriving (Show,GHC.Generic)
instance Generic MyAwesomeType -- this Generic is from generics-sop
awesomeFromList :: forall c r xs. (Generic r, Code r ~ '[xs], All ((~) c) xs)
=> [c]
-> Maybe r
awesomeFromList fields =
to . SOP . Z . hcliftA (Proxy :: Proxy ((~) c)) (mapKI id)
<$>
Generics.SOP.fromList fields
适用于实施Generics.SOP.Generic
的任何统一记录。
*Main> awesomeFromList ["foo","bar","baz"] :: Maybe MyAwesomeType
Just (MyAwesomeType {a = "foo", b = "bar", c = "baz"})