3

I have data type

data Constants = Constants { x1 :: Int, x2 :: Int, ... , x100 :: Int }

Names x1, x2, ..., x100 may have irregular naming.

Is there an elegant way to create Constants object from list of 100 Int values?

mkConstants :: [Int] -> Constants
mkConstants [x1, x2, ..., x100] = Constants x1 x2 ... x100 -- The bad way

What about reverse task?

extractInts :: Constants -> [Int]
extractInts (Constants x1 x2 ... x100) = [x1, x2, ..., x100] -- The bad way
5
  • 2
    Short answer: no. Where is the list coming from? In general, whenever I see lists that have to be a certain size (100 elements in this case) I get a bit suspicious about the use of a list.. Maybe just build up Constants where you are currently making the list? Commented Jul 8, 2016 at 16:27
  • 1
    Constants is example of type with big number of fields. Really example: stackage.org/haddock/lts-6.6/ghc-7.10.3/… Commented Jul 8, 2016 at 16:30
  • List is coming from IO action Commented Jul 8, 2016 at 16:31
  • A recursive use of function currying might make this doable. I can type up an answer but won't have time to check it if you want. Commented Jul 8, 2016 at 16:35
  • I check your solution. Please, answer. Commented Jul 8, 2016 at 16:50

2 Answers 2

8

Edit: see Reading long data structure in Haskell for a modified version when the record fields are of different types (i.e. not all ints).


One possibility would be to use type classes:

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

then, if the list is of the right size:

\> cons Constants [1..5]
Just (Constants {a = 1, b = 2, c = 3, d = 4, e = 5})

and otherwise you get nothing:

\> cons Constants [1..4]
Nothing
\> cons Constants [1..6]
Nothing
Sign up to request clarification or add additional context in comments.

2 Comments

It's really very simple solution. Can you post solution for reverse task - from Constants to [Int]?
@Bet the reverse would be an entirely different thing, and would probably require template Haskell (which i do not know). I would suggest to roll-back your added edit and ask the reverse case in a new question.
3

Here is a proof-of-concept way to do this via generic programming (in this case, via generics-sop). Whether this is a suitable approach to solve your actual problem depends on a lot of factors that I currently cannot judge:

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

In GHCi (this is with version 7.10.3, see below):

*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]

Interestingly, when I tried to compile this with ghc-8.0.1 (then you have to replace the -fcontext-stack option with -freduction-depth, too), I got an unexpected internal GHC error which I have to investigate further ...

6 Comments

The bug I got could be identical to ghc.haskell.org/trac/ghc/ticket/12041 which seems to be fixed.
I added the opposite direction. (But the other solution is certainly simpler.)
I can't compile your code. ghc-7.10.3 try to compile it already 10 minutes and memory usage 3 Gb!
@Bet Strange. I know there have been issues with compiler performance when deriving Generic for large datatypes, but I don't seem to hit this here. For me, it takes 2 seconds with -O0, and 6 seconds with -O1 and O2.
After 15 minutes of waiting ghc compile it. Strangely. The code is very little, but memory and processor usage is very big.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.