Как полностью оценить рекурсивный тип данных, используя Control.DeepSeq в Haskell? - PullRequest
0 голосов
/ 22 октября 2018

Я пытаюсь сравнить (с Criterion ) функцию, которая использует рекурсивный тип данных.Я нашел похожий вопрос с ответом, который мне не удалось подать в моем деле.Для нерекурсивных типов данных работает следующее:

data ExampleDataType1 a = 
    ValueConst1 String String String String 
  | ValueConst2 String String
  | ValueConst3 a
  | ValueConst4 String        
deriving (Show, Eq, Ord)


instance DeepSeq.NFData a => DeepSeq.NFData (ExampleDataType1 a) where
    rnf (ValueConst1 c1 c2 c3 c4) = DeepSeq.rnf c1 `seq` DeepSeq.rnf c2 `seq` DeepSeq.rnf c3 `seq` DeepSeq.rnf c4
    rnf (ValueConst2 c1 c2)       = DeepSeq.rnf c1 `seq` DeepSeq.rnf c2
    rnf (ValueConst3 c1)          = DeepSeq.rnf c1
    rnf (ValueConst4 c2)          = DeepSeq.rnf c2 

Однако выполнение следующих действий:

infixl 6 :+: -- Addition
infixl 7 :*: -- Multiplication
data ExampleDataType2 a =

    ValueConst5 (ExampleDataType2 a) 
    | a :*: String    
    | (ExampleDataType2 a) :+: (ExampleDataType2 a)      
    | ValueConst6 String a     
    | ValueConst7 String a     
    deriving (Show, Eq, Ord)

type MapExample a b = Map.Map String (Either (ExampleDataType1 a) (ExampleDataType2 b))

data ExampleDataType3 a b = ExampleDataType3 {
    start :: String,
    mapList :: [MapExample a b]

    } deriving Show


instance DeepSeq.NFData a => DeepSeq.NFData (ExampleDataType1 a) where
    rnf (ValueConst1 c1 c2 c3 c4) = DeepSeq.rnf c1 `seq` DeepSeq.rnf c2 `seq` DeepSeq.rnf c3 `seq` DeepSeq.rnf c4
    rnf (ValueConst2 c1 c2)       = DeepSeq.rnf c1 `seq` DeepSeq.rnf c2
    rnf (ValueConst3 c1)          = DeepSeq.rnf c1
    rnf (ValueConst4 c2)          = DeepSeq.rnf c2 

instance DeepSeq.NFData b => DeepSeq.NFData (ExampleDataType2 b) where
    rnf (ValueConst5 c1)           = DeepSeq.rnf c1
    rnf (val1 :+: val2)            = DeepSeq.rnf val1 `seq` DeepSeq.rnf val2
    rnf (val :*: str)              = DeepSeq.rnf val `seq` DeepSeq.rnf str
    rnf (ValueConst6 str val)      = DeepSeq.rnf str `seq` DeepSeq.rnf val
    rnf (ValueConst7 str val)      = DeepSeq.rnf str `seq` DeepSeq.rnf val

instance (DeepSeq.NFData a, DeepSeq.NFData b) => DeepSeq.NFData (ExampleDataType3 a b) where
    rnf (ExampleDataType3 s lst) =  DeepSeq.rnf s `seq` DeepSeq.rnf lst

приводит к ошибке при вызове функции nf для Criterion.Main для функции, которую я хочу сравнить с подписью testFunction :: (Show a1, Integral a1, Num a2, Eq a2) => [[a1]] -> ExampleDataType3 a2 a1:

• Ambiguous type variable ‘a20’ arising from a use of ‘nf’
      prevents the constraint ‘(Control.DeepSeq.NFData
                                  a20)’ from being solved.
      Probable fix: use a type annotation to specify what ‘a20’ should be.
      These potential instances exist:
        instance [safe] (Control.DeepSeq.NFData a,
                         Control.DeepSeq.NFData b) =>
                        Control.DeepSeq.NFData (Either a b)
          -- Defined in ‘Control.DeepSeq’
        instance (Control.DeepSeq.NFData k, Control.DeepSeq.NFData a) =>

                 Control.DeepSeq.NFData (Map.Map k a)
          -- Defined in ‘Data.Map.Internal’
        instance Control.DeepSeq.NFData a =>
                 Control.DeepSeq.NFData (Set.Set a)
          -- Defined in ‘Data.Set.Internal’
        ...plus 20 others
        ...plus 150 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)

Буду признателен за каждый ответ о том, как полностью оценить рекурсивный тип данных.

Редактировать 1:

Вызов теста, который вызывает ошибку:

main = defaultMain [
            bgroup "TestCases" [ bench "Case 1" $ nf testFunction [[1,0,1,1],[0,0,0,1],[1,1,1,0],[0,1,0,1]]
                         ]]

Функция testFunction выполняет свою работу, как требуется, за исключением того, что я не могу полностью оценить рекурсивный тип данных, так что функция nfКритерий может принять мою функцию в качестве входа.Поэтому я хотел бы избежать изменения типа данных.

1 Ответ

0 голосов
/ 22 октября 2018

Вы можете добавить сигнатуру типа в testFunction, где вы передадите ее nf.Что-то вроде:

nf (testFunction :: [[Int]] -> ExampleDataType3 Double Int) [[1,0,1,1],[0,0,0,1],[1,1,1,0],[0,1,0,1]]

Я выбрал тип Double;Вы можете выбрать другой тип.Поскольку существует несколько вариантов, GHC выдает ошибку Ambiguous type variable, а не выбирает ее произвольно.

...