【问题标题】:Constructing Haskell data types with many fields构造具有多个字段的 Haskell 数据类型
【发布时间】:2016-07-08 16:12:46
【问题描述】:

我有数据类型

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

【问题讨论】:

  • 简短回答:不。列表来自哪里?一般来说,每当我看到必须具有一定大小的列表(在这种情况下为 100 个元素)时,我都会对列表的使用产生一点怀疑。也许只是在您当前正在制作列表的地方建立 Constants
  • Constants 是具有大量字段的类型示例。真实示例:stackage.org/haddock/lts-6.6/ghc-7.10.3/…
  • 列表来自 IO 操作
  • 函数柯里化的递归使用可能使这成为可能。我可以输入一个答案,但如果你愿意,我没有时间检查它。
  • 我检查您的解决方案。请回答。

标签: haskell constructor algebraic-data-types


【解决方案1】:

编辑:当记录字段为不同类型(即并非所有整数)时,请参阅 Reading long data structure in Haskell 以获取修改后的版本。


一种可能性是使用类型类:

{-# 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

【讨论】:

  • 这真的是非常简单的解决方案。您可以发布反向任务的解决方案 - 从常量到 [Int]?
  • @Bet 反过来将是完全不同的事情,并且可能需要模板 Haskell(我不知道)。我建议回滚您添加的编辑并在新问题中提出相反的情况。
【解决方案2】:

这是一种通过通用编程(在本例中是通过generics-sop)实现此目的的概念验证方法。这是否适合解决您的实际问题取决于很多我目前无法判断的因素:

{-# 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 版本,见下文):

*Constants> test1
Constants {x00 = 1, x01 = 2, x02 = 3, x03 = 4, x04 = 5, x05 = 6, x06 = 7, x07 = 8, x08 = 9, x09 = 10, x10 = 11, x11 = 12, x12 = 13, x13 = 14, x14 = 15, x15 = 16, x16 = 17, x17 = 18, x18 = 19, x19 = 20, x20 = 21, x21 = 22, x22 = 23, x23 = 24, x24 = 25, x25 = 26, x26 = 27, x27 = 28, x28 = 29, x29 = 30, x30 = 31, x31 = 32, x32 = 33, x33 = 34, x34 = 35, x35 = 36, x36 = 37, x37 = 38, x38 = 39, x39 = 40, x40 = 41, x41 = 42, x42 = 43, x43 = 44, x44 = 45, x45 = 46, x46 = 47, x47 = 48, x48 = 49, x49 = 50, x50 = 51, x51 = 52, x52 = 53, x53 = 54, x54 = 55, x55 = 56, x56 = 57, x57 = 58, x58 = 59, x59 = 60, x60 = 61, x61 = 62, x62 = 63, x63 = 64, x64 = 65, x65 = 66, x66 = 67, x67 = 68, x68 = 69, x69 = 70, x70 = 71, x71 = 72, x72 = 73, x73 = 74, x74 = 75, x75 = 76, x76 = 77, x77 = 78, x78 = 79, x79 = 80, x80 = 81, x81 = 82, x82 = 83, x83 = 84, x84 = 85, x85 = 86, x86 = 87, x87 = 88, x88 = 89, x89 = 90, x90 = 91, x91 = 92, x92 = 93, x93 = 94, x94 = 95, x95 = 96, x96 = 97, x97 = 98, x98 = 99, x99 = 100}
*Constants> test2
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100]

有趣的是,当我尝试用 ghc-8.0.1 编译它时(那么你也必须用 -freduction-depth 替换 -fcontext-stack 选项),我遇到了一个意外的内部 GHC 错误,我必须进一步调查。 ..

【讨论】:

  • 我得到的错误可能与ghc.haskell.org/trac/ghc/ticket/12041 相同,似乎已修复。
  • 我添加了相反的方向。 (但另一种解决方案肯定更简单。)
  • 我无法编译你的代码。 ghc-7.10.3 尝试编译它已经 10 分钟和内存使用 3 Gb!
  • @Bet Strange。我知道在为大型数据类型导出 Generic 时,编译器性能存在问题,但我似乎没有在这里遇到这个问题。对我来说,-O0 需要 2 秒,-O1O2 需要 6 秒。
  • 等待 ghc 15 分钟后编译它。奇怪的是。代码很少,但内存和处理器使用量很大。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-14
  • 1970-01-01
  • 1970-01-01
  • 2014-05-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多