1

我有一个这样的样本类型:

data Sample_Type = Sample_Type { field1 :: Int,
                                 field2 :: Int,
                                 field3 :: [Int]
                               } deriving (Show, Eq)

我正在使用此函数field3在记录中附加列表:

insertPlan :: [Sample_Type] -> Sample_Type -> Int -> [Sample_Type]
insertPlan [] _ _ = []
insertPlan (x:xs) y b = if (x == y)
                        then (y {field3 = b:(field3 y)}):xs
                        else x:(insertPlan xs y b)

我正在尝试将上述函数转换为更通用的形式(因为我有许多记录数据类型,其中有一个列表需要更新)。

我想出了以下一段代码,但这不起作用(显然):

insertVariant :: [a] -> a -> (a -> [Int]) -> Int -> [a]
insertVariant (x:xs) a f b  = if (x == a)
                              then (a {f = b:(f a)}):xs
                              else x:(insertVariant xs a b)

有什么好办法解决这个问题吗?

4

2 回答 2

1

您可以尝试以下方法:

data Sample_Type = Sample_Type { field1 :: Int,
                                 field2 :: Int,
                                 field3 :: [Int]
                               } deriving (Show, Eq)



insertVariant :: Eq a => [a] -> a -> (a -> Int -> a) -> Int -> [a]
insertVariant l a f i = map (\x -> if x == a then f x i else x) l

main = print $ insertVariant [Sample_Type 1 2 []] (Sample_Type 1 2 []) (\s i -> s {field3 = i:(field3 s)}) 10

(\s i -> s {field3 = i:(field3 s)})您可以使用 Lens 包摆脱。镜头将为您提供记录字段的 getter 和 setter,以便您可以将镜头传递给(a -> Int -> a)参数

于 2013-10-06T09:33:13.910 回答
1

类型类是一种解决方案,但您需要MultiParamTypeClasses扩展:

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}

class Insertable i a where
    insertInto :: i -> a -> i


data SampleType = SampleType
    { field1 :: Int
    , field2 :: Int
    , field3 :: [Int]
    } deriving (Show, Eq)

instance Insertable SampleType Int where
    insertInto (SampleType f1 f2 f3) x = SampleType f1 f2 (x:f3)

data MyType = MyType
    { mtField1 :: String
    , mtField2 :: [String]
    } deriving (Show, Eq)

instance Insertable MyType String where
    insertInto (MyType f1 f2) x = MyType f1 (x:f2)

insertPlan :: (Eq i, Insertable i a) => [i] -> i -> a -> [i]
insertPlan [] _ _ = []
insertPlan (x:xs) y b =
    if x == y
        then insertInto y b : xs
        else x : insertPlan xs y b


main = do
    let s = SampleType 1 2 [1..5]
        m = MyType "Testing" ["world"]
    print $ insertPlan [s] s (6 :: Int)
    print $ insertPlan [m] m "Hello"

需要注意的几点:

  1. FlexibleInstancesis forinstance MyType String因为String是 的类型同义词[Char],所以编译器在没有这个扩展的情况下拒绝它。
  2. 我必须指定 的类型6,否则编译器无法确定6应该是什么类型。
  3. 您可以在没有 的情况下编写它MultiParamTypeClasses,但是您insertInto无法对插入到列表中的内容进行类型检查。不过,还有其他解决方案。
于 2013-10-06T00:26:02.533 回答