2010-11-23 23 views
2

私があなたを助けてくれることを願っています。私は何年もの命令的言語の後にハスケルのノブですので、もし私がばかな間違いをしているなら、それを説明して、私は学ぶことができます。私は、データベースクエリの結果から、この型のインスタンスを構築IO Monadでレコードの更新に失敗しましたか?

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

は、私は次のデータ型を持っています。結果がsourceDicomフィールドに来るとき、私はそれをMaybe値にしたので、何の値も持てません。問題は、EncapDicomObjectをロードして結果のデータ型を更新しようとするときに発生します。そのため、アクセスするたびにEncapDicomObjectをディスクからロードする必要はありません。

次は、この問題を引き起こすコードです。私の意図は、EncapDicomObjectが読み込まれているかどうか、既存の(Just)値を使用するかどうか(Nothingが検出されていない場合)を読み込み、NothingをJustに変更するかどうかをテストすることです。私はマークされた行をコメントアウトした場合面倒ラインが「**」

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() 

でマークされ、その後のコードはコンパイルが、それは常に何に遭遇しないので、それは毎回ファイルをロードします。持っている)(私はSTMTがsopInstを更新し、IOを返すように関数を作成する代わりに、IO()しかし、すべての私の試みのDicomSopInstanceを返すという意味として解釈

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} 

:私はコメントを解除した場合、私は次のエラーを取得します失敗しました。

私には何が欠けていますか? Haskellの非厳密な動作が私のためにやるか、あるいは単に間違った設計をしたときに、オンデマンドの負荷をかけようとしていますか?変更可能な変数にsourceDicomを変換する私の試みは、同様に無駄になってきた:(

歓声

ジェームズ

+0

将来は、コードを4つのスペースでインデントしてください。コードボタン(1と1が付いたコードボタン)を使用すると、コードの形式が正しく設定されます。 – sepp2k

+0

Ack :(AdBlockは私からインターフェイスの多くを隠していた)固定された私は願っています –

答えて

4

をあなたは非常に機能的なパラダイムを理解していない。sopInstは、あなたの関数の先頭で定義されますその値は石で設定されていますが、その値を後で変更することはできません。代わりに、元のものの変更されたバージョンである別のものに名前を割り当てることができます。たとえば、次のようになります。

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

物事は不変なので、多くの共有が進行中であることに注意してください。あなたのSopInstタイプがCのレコードであるとしましょう。概念的には、すべてのメンバーへのポインタを持っています。 newSopInstを作成すると、そのポインタのレコードのコピーが得られます.1つのポインタはsourceDicomの新しい値を指しています。他のフィールドが指す値は共有されています。これは、プログラミングのこのスタイル(迂回の必要性 - とにかく怠惰に必要)は、あなたが恐れるかもしれないよりはるかに非効率的であり、ボーナスとして、あなたはまだ別の場所にそれを必要とする場合は、古いsopInstをぶら下げていることを意味します。 (もしあなたがいなければ、もちろん、それはガベージコレクションされます)。

+0

あなたはおそらく一般的な意味で正しいと思います、私はまだ学んでいます 私はいつ書きましたか私はsourceDicomを置き換えるコードだが、おそらくそれほど多くはないので、私はsopInstを置き換えるだろう。私は小さな構造物と古いものを集めるゴミを交換することに心地よかったです。 –

+0

*一度これを掛けている おそらく私が尋ねるべきことは、「ファイルを読み込むときにこれらのオブジェクトを更新する必要があります。どうすればいいですか」 私のハスケルは限られていますが、値を更新すると上書きすることに気付いていましたが、それは私の意図でした。私はちょうど変更を維持する方法を把握したい –

+0

ああ!そうですか!渡されたDicomImageを更新したい!それをしないでください! 'return(image {sopInstance = newSopInst})'を呼び出して、関数に 'showImage :: TextCtrl t - > DicomImage - > IO DicomImage'の型を与えます。あなたは常にMVar/IORefで本当の可変状態を使うことができますが、早い段階で「正しい」方法を習得し、MVars/IORefを本当に必要なときに使用するほうがますます優れています(一般的に並行性や面白いタイプffiの)。 – sclv

関連する問題