用多字段构造Haskell数据类型
我有数据类型用多字段构造Haskell数据类型,haskell,constructor,algebraic-data-types,Haskell,Constructor,Algebraic Data Types,我有数据类型 data Constants = Constants { x1 :: Int, x2 :: Int, ... , x100 :: Int } 名称x1、x2、…、x100可能具有不规则的命名 有没有一种优雅的方法可以从100个Int值的列表中创建Constants对象 mkConstants :: [Int] -> Constants mkConstants [x1, x2, ..., x100] = Constants x1 x2 ... x100 -- The bad
data Constants = Constants { x1 :: Int, x2 :: Int, ... , x100 :: Int }
名称x1、x2、…、x100可能具有不规则的命名
有没有一种优雅的方法可以从100个Int值的列表中创建Constants对象
mkConstants :: [Int] -> Constants
mkConstants [x1, x2, ..., x100] = Constants x1 x2 ... x100 -- The bad way
反向任务呢
extractInts :: Constants -> [Int]
extractInts (Constants x1 x2 ... x100) = [x1, x2, ..., x100] -- The bad way
下面是一种通过泛型编程(在本例中是通过)实现这一点的概念验证方法。这是否是解决您实际问题的合适方法取决于许多我目前无法判断的因素:
{-# LANGUAGE DeriveGeneric, ScopedTypeVariables, DataKinds, TypeFamilies, FlexibleContexts, TypeOperators, PolyKinds #-}
{-# OPTIONS_GHC -fcontext-stack=200 #-}
module Constants where
import Data.Maybe
import Generics.SOP
import qualified GHC.Generics as G
data Constants =
Constants
{ x00 :: Int, x01 :: Int, x02 :: Int, x03 :: Int, x04 :: Int, x05 :: Int, x06 :: Int, x07 :: Int, x08 :: Int, x09 :: Int
, x10 :: Int, x11 :: Int, x12 :: Int, x13 :: Int, x14 :: Int, x15 :: Int, x16 :: Int, x17 :: Int, x18 :: Int, x19 :: Int
, x20 :: Int, x21 :: Int, x22 :: Int, x23 :: Int, x24 :: Int, x25 :: Int, x26 :: Int, x27 :: Int, x28 :: Int, x29 :: Int
, x30 :: Int, x31 :: Int, x32 :: Int, x33 :: Int, x34 :: Int, x35 :: Int, x36 :: Int, x37 :: Int, x38 :: Int, x39 :: Int
, x40 :: Int, x41 :: Int, x42 :: Int, x43 :: Int, x44 :: Int, x45 :: Int, x46 :: Int, x47 :: Int, x48 :: Int, x49 :: Int
, x50 :: Int, x51 :: Int, x52 :: Int, x53 :: Int, x54 :: Int, x55 :: Int, x56 :: Int, x57 :: Int, x58 :: Int, x59 :: Int
, x60 :: Int, x61 :: Int, x62 :: Int, x63 :: Int, x64 :: Int, x65 :: Int, x66 :: Int, x67 :: Int, x68 :: Int, x69 :: Int
, x70 :: Int, x71 :: Int, x72 :: Int, x73 :: Int, x74 :: Int, x75 :: Int, x76 :: Int, x77 :: Int, x78 :: Int, x79 :: Int
, x80 :: Int, x81 :: Int, x82 :: Int, x83 :: Int, x84 :: Int, x85 :: Int, x86 :: Int, x87 :: Int, x88 :: Int, x89 :: Int
, x90 :: Int, x91 :: Int, x92 :: Int, x93 :: Int, x94 :: Int, x95 :: Int, x96 :: Int, x97 :: Int, x98 :: Int, x99 :: Int
}
deriving (Show, G.Generic)
instance Generic Constants
fromConstantList ::
forall a c xs . (Generic a, Code a ~ '[ xs ], All ((~) c) xs) =>
[c] -> a
fromConstantList =
to . SOP . Z . hcmap (Proxy :: Proxy ((~) c)) (I . unK) . fromJust . fromList
toConstantList ::
forall a c xs . (Generic a, Code a ~ '[ xs ], All ((~) c) xs) =>
a -> [c]
toConstantList =
hcollapse . hcmap (Proxy :: Proxy ((~) c)) (K . unI) . unZ . unSOP . from
unZ :: NS f (x ': xs) -> f x
unZ (Z x) = x
test1 :: Constants
test1 = fromConstantList [1..100]
test2 :: [Int]
test2 = toConstantList test1
在GHCi中(版本7.10.3,见下文):
有趣的是,当我试图用ghc-8.0.1编译这篇文章时(然后你也必须用-freducation depth
替换-fcontext stack
选项),我得到了一个意外的内部ghc错误,我必须进一步调查这个错误…编辑:有关记录字段类型不同时的修改版本,请参阅(即并非所有INT)
一种可能是使用类型类:
{-# LANGUAGE FlexibleInstances #-}
data Constants = Constants { a :: Int, b :: Int, c :: Int, d :: Int, e :: Int }
deriving Show
class Cons a where
cons :: a -> [Int] -> Maybe Constants
instance Cons Constants where
cons c [] = Just c
cons _ _ = Nothing
instance (Cons a) => Cons (Int -> a) where
cons f (x:xs) = cons (f x) xs
cons _ _ = Nothing
然后,如果列表大小正确:
\> cons Constants [1..5]
Just (Constants {a = 1, b = 2, c = 3, d = 4, e = 5})
否则你什么也得不到:
\> cons Constants [1..4]
Nothing
\> cons Constants [1..6]
Nothing
简短回答:否。列表来自哪里?通常,每当我看到必须具有一定大小的列表时(本例中为100个元素)我对列表的使用有点怀疑..也许只是在您当前创建列表的位置建立
常量
?常量是一个具有大量字段的类型示例。真正的示例:列表来自IO操作递归使用函数curry可能会使这成为可能。我可以键入答案,但没有时间检查I如果你愿意的话。我检查你的解决方案。请回答。我得到的bug可能与似乎已修复的bug相同。我添加了相反的方向。(但另一个解决方案肯定更简单。)我无法编译您的代码。ghc-7.10.3尝试编译它已经10分钟了,内存使用量为3 Gb!@Bet奇怪。我知道在为大型数据类型派生泛型时编译器性能有问题,但我似乎没有在这里找到答案。对我来说,-O0
需要2秒,而-O1
和O2
。等待ghc 15分钟后编译。奇怪的是,代码非常少,但内存和处理器使用量非常大。这真的是一个非常简单的解决方案。你能为反向任务发布解决方案吗?从常量到[Int]?@打赌反向将是完全不同的事情,可能需要模板Haskell(我不知道)。我建议将添加的编辑回滚,并在新问题中询问相反的情况。
\> cons Constants [1..4]
Nothing
\> cons Constants [1..6]
Nothing