Nano Hash - криптовалюты, майнинг, программирование

Записать ошибку обновления в IO Monad?

Я надеюсь, что вы можете мне помочь. Я новичок в Haskell после многих лет императивных языков, поэтому, если я делаю глупую ошибку, объясните ее, чтобы я мог учиться.

У меня есть следующий тип данных:

data DicomSopInstance = DicomSopInstance {
sopInstancePath :: String,
sopInstanceUid :: String,
sopInstancePk :: Int64,
seriesFk :: Int64,
sopInstanceFrameCount :: Int32,
sourceDicom :: Maybe EncapDicomObject
}

Я создаю экземпляры этого типа из результатов запроса к базе данных. Когда результаты приходят в поле sourceDicom, оно не может иметь никакого значения, поэтому я сделал его значением «Может быть». Проблема возникает, когда я пытаюсь загрузить EncapDicomObject и обновить тип данных с результатом, поэтому мне не нужно загружать EncapDicomObject с диска каждый раз, когда я хочу получить к нему доступ.

Ниже приведен код, вызывающий проблему. Мое намерение состоит в том, чтобы проверить, был ли EncapDicomObject прочитан с диска, если он был загружен, используйте существующее (просто) значение, если нет (ничего не обнаружено), затем загрузите его и измените ничего на просто. Проблемная строка отмечена "**"

showImage :: TextCtrl t -> DicomImage -> IO ()
showImage textCtl image = do
  let sopInst = sopInstance image
  let maybeEncapDicom = sourceDicom sopInst
  case maybeEncapDicom of
  Just encapDicom -> do
    showEncapDicomObject textCtl encapDicom (sopInstancePath sopInst)
    return ()
  Nothing         -> do
    eitherDicom <- readDicomFile $ sopInstancePath sopInst
    case eitherDicom of
      Left errorMessage -> do
        infoM "Hastur" $ "Error reading DICOM file: " ++
          (sopInstancePath sopInst) ++ " - " ++ errorMessage
        textCtrlSetValue textCtl $ "*** DICOM: " ++
          (sopInstancePath sopInst) ++ " ***\n"
        textCtrlAppendText textCtl errorMessage
        textCtrlAppendText textCtl "\n*** [End] ***"
        textCtrlShowPosition textCtl 0
        return ()
      Right encapDicom  -> do
      sopInst { sourceDicom = Just encapDicom } -- ****
        showEncapDicomObject textCtl encapDicom (sopInstancePath sopInst)
        return ()

Если я закомментирую отмеченную строку, код компилируется, но каждый раз загружает файл, так как всегда ничего не встречает. Если я раскомментирую, я получаю следующую ошибку:

src\Hastur.hs:382:10:
    Couldn't match expected type `IO a'
           against inferred type `DicomSopInstance'
    In a stmt of a 'do' expression:<br>
        sopInst {sourceDicom = Just encapDicom}

Я интерпретирую это как означающее, что stmt возвращает DicomSopInstance вместо IO(), но все мои попытки создать функцию для обновления sopInst и возврата IO() не увенчались успехом.

Что мне не хватает? Пытаюсь ли я выполнить загрузку по требованию, когда нестрогое поведение Haskell сделает это за меня, или у меня просто неправильный дизайн? Мои попытки преобразовать sourceDicom в изменяемую переменную также ни к чему не привели :(

ваше здоровье

Джеймс

23.11.2010

  • В будущем, пожалуйста, делайте отступ в своем коде четырьмя пробелами или используйте кнопку кода (ту, что с единицами и нулями), чтобы ваш код был правильно отформатирован. 23.11.2010
  • Акк :( AdBlock скрывал от меня большую часть интерфейса. Надеюсь исправлено. 23.11.2010

Ответы:


1

Вы не совсем понимаете функциональную парадигму. sopInst определяется в верхней части вашей функции. Внутри него нет изменяемых ссылок — его значение заложено в камне. Вы не сможете изменить это значение позже. Вместо этого вы можете присвоить имя другой вещи, которая является измененной версией оригинальной. Попробуйте, например, следующее.

Right encapDicom  -> do
  let newSopInst = sopInst { sourceDicom = Just encapDicom }
  showEncapDicomObject textCtl encapDicom (sopInstancePath newSopInst)
  return ()

Обратите внимание, что, поскольку вещи неизменны, происходит много обмена. Представьте, что ваш тип SopInst является записью в C. Концептуально он имеет указатели на все свои члены. Когда вы создаете newSopInst, вы просто получаете копию этой записи указателей, причем один указатель теперь указывает на новое значение для sourceDicom — значения, на которые указывают другие поля, являются общими. Это означает, что этот стиль программирования (за счет большего количества косвенных действий — в любом случае, вызванных ленью) гораздо менее неэффективен, чем вы можете опасаться, и в качестве бонуса у вас все еще есть старый sopInst, если он вам понадобится где-то еще. (Если вы этого не сделаете, конечно, он будет собирать мусор).

23.11.2010
  • Спасибо за ответ. Я думаю, что вы, вероятно, правы в общем смысле, я все еще учусь. Когда я писал код, я понимал, что буду заменять sourceDicom, но, возможно, не настолько, чтобы заменять sopInst. Меня устраивала замена небольшой конструкции и сбор мусора старой. 24.11.2010
  • вздох все еще осваиваю это Возможно, я должен был спросить: мне нужно обновить эти объекты при загрузке файла, как я могу это сделать? Мой Haskell ограничен, но я понял, что обновление значения перезаписывает его, но это было моим намерением. Я просто хочу выяснить, как сохранить изменения 24.11.2010
  • Ой! Я понимаю! Вы хотите обновить DicomImage, который вы передали! Не делай этого! Просто return (image {sopInstance = newSopInst}) и присвойте вашей функции тип showImage :: TextCtrl t -> DicomImage -> IO DicomImage. Вы всегда можете схитрить и использовать настоящее изменяемое состояние с MVar/IORef, но гораздо лучше заранее освоить правильный путь и использовать MVars/IORefs только тогда, когда это действительно необходимо (как правило, либо с параллелизмом, либо с некоторыми забавными типами ffi). ). 24.11.2010
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..