genCheckable :: HSStruct -> String
-- genCheckable (HSStruct name types) = concat [fst_line, fields_line, offsets_line, size_line, alignment_line, new_line]
genCheckable (HSStruct name types) = concat [fst_line, fields_line, offsets_lines, size_line, alignment_line, new_line]
    where fst_line       = concat ["instance Checkable ", name, " where\n"]
          fields_line    = concat ["    checkFields    ptr1 ptr2 = (==1) <$> checkFields",name," ptr1 ptr2\n"]
          -- offsets_line   = concat ["    checkOffsets   _    offs = (==1) <$> checkOffsets",name," offs\n"]
          size_line      = concat ["    getSize        a          = fromIntegral <$> getSize",name,"\n"]
          alignment_line = concat ["    getAlignment   a          = fromIntegral <$> getAlignment",name,"\n"]
          --- news
          new_line'       = case length types of
              0 -> new_fn 0 []
              1 -> new_fn 0 $ head types
              n -> concat $ zipWith new_fn [1..] types
          new_line       = new_line' ++ "\n"
          new_fn ix tps  = concat ["    new ",pattern_match ix tps, " = do\n", do_vars ix tps] 
          ---
          offsets_lines     = case length types of
              0 -> offsets_fn 0 []
              1 -> offsets_fn 0 $ head types
              n -> concat $ zipWith offsets_fn [1..] types
          offsets_fn 0  tps  = concat ["    checkOffsets   _    offs = (==1) <$> checkOffsets",name," offs\n"]
          offsets_fn ix tps  = concat ["    checkOffsets ", pattern_match ix tps, " offs = (==1) <$> checkOffsets",name, s_ix ix, " offs\n"]
          ---
          variables tps  = map return $ take (length tps) ['a'..'z']
          is_prs    tps  = map snd tps
          constr_vars var ptrs = concat $ intersperse " " $ zipWith (\v is_pr -> if is_pr then v else "ptr_"++v) var ptrs
          do_vars ix tps  = do
              let vars        = variables tps
                  prs         = is_prs tps
                  constants   = constr_vars vars prs
                  the_vars    = map fst $ filter (not.snd) $ zip vars prs
                  ptr_vars    = map (\v -> "ptr_"++v) the_vars
                  alloc_lines = zipWith (\ptr var -> concat ["        ", ptr, " <- newStorable " , var,"\n"]) ptr_vars the_vars
                  the_new_line= concat ["        ptr <- new",name,s_ix ix, " ", constants,"\n"]
                  free_lines  = map (\ptr -> concat ["        free ",ptr,"\n"]) ptr_vars
                  papa_line   = "        return ptr\n"
              concat $ [concat alloc_lines, the_new_line, concat free_lines, papa_line]
          pattern_match ix tps = concat ["(",name,s_ix ix," ", concat $ intersperse " " $ variables tps, ")"]
genCheckable :: HSStruct -> String
genCheckable (HSStruct name types) = concat [fst_line, fields_line, offsets_lines, size_line, alignment_line, new_line]
    where fst_line       = concat ["instance Checkable ", name, " where\n"]
          fields_line    = concat ["    checkFields    ptr1 ptr2 = (==1) <$> checkFields",name," ptr1 ptr2\n"]
          -- offsets_line   = concat ["    checkOffsets   _    offs = (==1) <$> checkOffsets",name," offs\n"]
          size_line      = concat ["    getSize        a          = fromIntegral <$> getSize",name,"\n"]
          alignment_line = concat ["    getAlignment   a          = fromIntegral <$> getAlignment",name,"\n"]
          --- news
          new_line'       = case length types of
              0 -> new_fn 0 []
              1 -> new_fn 0 $ head types
              n -> concat $ zipWith new_fn [1..] types
          new_line       = new_line' ++ "\n"
          new_fn ix tps  = concat ["    new ",pattern_match ix tps, " = do\n", do_vars ix tps] 
          ---
          offsets_lines     = case length types of
              0 -> offsets_fn 0 []
              1 -> offsets_fn 0 $ head types
              n -> concat $ zipWith offsets_fn [1..] types
          offsets_fn 0  tps  = concat ["    checkOffsets   _    offs = (==1) <$> checkOffsets",name," offs\n"]
          offsets_fn ix tps  = concat ["    checkOffsets ", pattern_match ix tps, " offs = (==1) <$> checkOffsets",name, s_ix ix, " offs\n"]
          ---
          variables tps  = map return $ take (length tps) ['a'..'z']
          is_prs    tps  = map snd tps
          constr_vars var ptrs = concat $ intersperse " " $ zipWith (\v is_pr -> if is_pr then v else "ptr_"++v) var ptrs
          do_vars ix tps  = do
              let vars        = variables tps
                  prs         = is_prs tps
                  constants   = constr_vars vars prs
                  the_vars    = map fst $ filter (not.snd) $ zip vars prs
                  ptr_vars    = map (\v -> "ptr_"++v) the_vars
                  alloc_lines = zipWith (\ptr var -> concat ["        ", ptr, " <- newStorable " , var,"\n"]) ptr_vars the_vars
                  the_new_line= concat ["        ptr <- new",name,s_ix ix, " ", constants,"\n"]
                  free_lines  = map (\ptr -> concat ["        free ",ptr,"\n"]) ptr_vars
                  papa_line   = "        return ptr\n"
              concat $ [concat alloc_lines, the_new_line, concat free_lines, papa_line]
          pattern_match ix tps = concat ["(",name,s_ix ix," ", concat $ intersperse " " $ variables tps, ")"]
genCheckable (HSStruct name types) = concat [fst_line, fields_line, offsets_lines, size_line, alignment_line, new_line]
    where fst_line       = concat ["instance Checkable ", name, " where\n"]
          fields_line    = concat ["    checkFields    ptr1 ptr2 = (==1) <$> checkFields",name," ptr1 ptr2\n"]
          -- offsets_line   = concat ["    checkOffsets   _    offs = (==1) <$> checkOffsets",name," offs\n"]
          size_line      = concat ["    getSize        a          = fromIntegral <$> getSize",name,"\n"]
          alignment_line = concat ["    getAlignment   a          = fromIntegral <$> getAlignment",name,"\n"]
          --- news
          new_line'       = case length types of
              0 -> new_fn 0 []
              1 -> new_fn 0 $ head types
              n -> concat $ zipWith new_fn [1..] types
          new_line       = new_line' ++ "\n"
          new_fn ix tps  = concat ["    new ",pattern_match ix tps, " = do\n", do_vars ix tps] 
          ---
          offsets_lines     = case length types of
              0 -> offsets_fn 0 []
              1 -> offsets_fn 0 $ head types
              n -> concat $ zipWith offsets_fn [1..] types
          offsets_fn 0  tps  = concat ["    checkOffsets   _    offs = (==1) <$> checkOffsets",name," offs\n"]
          offsets_fn ix tps  = concat ["    checkOffsets ", pattern_match ix tps, " offs = (==1) <$> checkOffsets",name, s_ix ix, " offs\n"]
          ---
          variables tps  = map return $ take (length tps) ['a'..'z']
          is_prs    tps  = map snd tps
          constr_vars var ptrs = concat $ intersperse " " $ zipWith (\v is_pr -> if is_pr then v else "ptr_"++v) var ptrs
          do_vars ix tps  = do
              let vars        = variables tps
                  prs         = is_prs tps
                  constants   = constr_vars vars prs
                  the_vars    = map fst $ filter (not.snd) $ zip vars prs
                  ptr_vars    = map (\v -> "ptr_"++v) the_vars
                  alloc_lines = zipWith (\ptr var -> concat ["        ", ptr, " <- newStorable " , var,"\n"]) ptr_vars the_vars
                  the_new_line= concat ["        ptr <- new",name,s_ix ix, " ", constants,"\n"]
                  free_lines  = map (\ptr -> concat ["        free ",ptr,"\n"]) ptr_vars
                  papa_line   = "        return ptr\n"
              concat $ [concat alloc_lines, the_new_line, concat free_lines, papa_line]
          pattern_match ix tps = concat ["(",name,s_ix ix," ", concat $ intersperse " " $ variables tps, ")"]