Repa Как сделать экземпляр Read?

Как лучше всего сделать

type Configuration = Array DIM1 (Double, Double, Double)

экземпляр чтения? Так что позже я мог вывести

data SimulationData = SD Configuration Double StdGen Int

быть экземпляром Read тоже.


person Yrogirg    schedule 24.12.2011    source источник
comment
Я подозреваю, что вы не можете сделать полный экземпляр Read. Как правило, важные типы данных уже будут иметь экземпляры Read, если автор считает, что они имеют смысл. Тип Array в Repa имеет функции более высокого порядка внутри своих компонентов — Generator и Range, которые нельзя сделать экземплярами Read. Я полагаю, что правильно будет сериализовать/десериализовать ваши данные в более простой формат.   -  person stephen tetley    schedule 24.12.2011


Ответы (1)


Такой экземпляр будет сиротским экземпляром, чего обычно следует избегать. Однако написать его довольно просто:

{-# LANGUAGE TypeOperators #-}

import Data.Array.Repa (Array, Shape, Elt, Z(..), (:.)(..))
import qualified Data.Array.Repa as R

instance Read Z where
  readsPrec _ r = do
    ("Z", s) <- lex r
    return (Z, s)

instance (Read tail, Read head) => Read (tail :. head) where
  readsPrec d =
    readParen (d > prec) $ \r -> do
      (tl, s) <- readsPrec (prec + 1) r
      (":.", t) <- lex s
      (hd, u) <- readsPrec (prec + 1) t
      return (tl :. hd, u)
    where prec = 3

instance (Shape sh, Read sh, Elt a, Read a) => Read (Array sh a) where
  readsPrec d =
    readParen (d > app) $ \r -> do
      ("Array", s) <- lex r
      (sh, t) <- readsPrec (app + 1) s
      (xs, u) <- readsPrec (app + 1) t
      return (R.fromList sh xs, u)
    where app = 10

Если вы используете расширение StandaloneDeriving, первые два экземпляра можно упростить:

deriving instance Read Z
deriving instance (Read tail, Read head) => Read (tail :. head)

Эти экземпляры, вероятно, должны быть в самой repa; Я просто основывал их на экземпляре примера, приведенном в Text.Show и вывод repa show. Я предлагаю сделать запрос функции на системе отслеживания ошибок repa и поместить эти экземпляры в модуль вашей программы на данный момент (если вы не хотите избежать экземпляры-сироты полностью, и в этом случае вам придется решать проблему совсем другим способом).


Тем не менее, вам, вероятно, следует подумать о простом преобразовании ваших данных в список (с toList) и его использовании; он избегает экземпляра-сироты и не должен иметь никаких недостатков. Вы также можете рассмотреть возможность использования «настоящей» библиотеки сериализации, такой как cereal, если вас больше интересует обработка данных с помощью код, чем то, что он должен быть удобочитаемым; Read обычно считается довольно ограниченным применением.

person ehird    schedule 24.12.2011
comment
Тип Array в Repa состоит из списка регионов, которые содержат Range и Generator, оба Range и Generator имеют функции более высокого порядка в качестве компонентов, поэтому их нельзя сделать экземплярами Read. - person stephen tetley; 24.12.2011
comment
@stephentetley: все, что должен уметь делать экземпляр Read, — это анализировать допустимый код Haskell, который выводит соответствующий экземпляр Show. - person ehird; 24.12.2011
comment
show $ R.fromFunction (Z :. (10::Int)) (const 42) = "Array (Z :. 10) [42.0,42.0,42.0,42.0,42.0,42.0,42.0,42.0,42.0,42.0]", что правильно анализирует мой экземпляр. - person ehird; 24.12.2011
comment
По общему признанию, экземпляр repa Show нарушает здесь правила, поскольку этот код не печатает, но это правило часто нарушается (например, Data.ByteString.Char8 экспортирует экземпляр Show для ByteStrings, который работает, только если вы включите OverloadedStrings, и я думаю, что экземпляр Show для lazy ByteStrings фактически использует неэкспортированные конструкторы). - person ehird; 24.12.2011
comment
@ehird: требование, чтобы Show и Read были семантически действительными, Haskell не имеет практического смысла. Однако синтаксис имеет значение, так как в противном случае было бы трудно определить корректно работающие экземпляры для типов контейнеров, таких как [a], которые должны взаимодействовать с экземплярами для типа элемента. - person hammar; 24.12.2011
comment
@hammar: Да, это справедливо. Я считаю, что Show в основном полезен только для отладки (для чего он, конечно, очень полезен), а Read полезен только для игрушечных программ, поэтому я могу ценить семантически правильные экземпляры больше, чем другие. - person ehird; 24.12.2011
comment
@ehird, есть проблема. Я не могу разобрать, например, Just arr, это дает мне *** Исключение: Prelude.read: нет разбора, хотя разбор самих массивов или кортежей работает. - person Yrogirg; 25.12.2011
comment
@Yrogirg: это ошибка в экземпляре Show repa: он показывает Just arr как Just Array (Z :. 10) [...] без необходимых скобок. Изменение readsPrec d = readParen (d > app) $ \r -> do на readsPrec d r = do должно заставить мой экземпляр работать в этом случае, но, к сожалению, то, что делает repa, вызывает внутреннюю двусмысленность; вы должны сообщить об этом как об ошибке. - person ehird; 25.12.2011