1

私はかなり単純なプロセッサ エミュレータを作成しようとしており、実際のプロセッサをそのメモリ インターフェイスから分離しようとしています。たとえば、古い TRS-80 には 12K の ROM があり、合計 16、32、または 48K の合計 RAM で構成できます。メモリ システムに関する私の最初のアイデアは、型クラスでした。

class MemorySystem memInternals addrType wordType where
  -- | General memory fetch. This always returns a 'wordType' value,
  -- even if the system's memory internals are byte addressable.
  mfetch :: addrType       -- ^ The address from which the instruction will be fetched
         -> memInternals   -- ^ The memory system
         -> wordType       -- ^ The fetched word

  -- | Fetch a block of words from the memory system
  mfetchN :: ( Unbox wordType
             ) =>
             addrType      -- ^ The address from which the instruction will be fetched
          -> Int           -- ^ Number of words to fetch
          -> memInternals  -- ^ The memory system
          -> Vector wordType -- ^ The words fetched

明確化: 要点はMemorySystem、命令デコーダ (TRS-80 の場合は Z80 命令デコーダ) がそのメモリ インターフェイスとは独立して動作できるようにすることですmfetch。オペランド。したがって、memInternals型クラス関数によって部分的に指定されたメモリ システムへのインターフェイスを実装する型です。

ポリモーフィックであることを許可しながら、つまり異なるメモリ構成を表すことを許可addrTypewordTypeながら、制約する最良の方法はどのようにするかです。次のような関数にコンテキストを追加していることに気づきました。memInteralsmemInternals

foo :: ( MemorySystem memSys Word16 Word8) =>
    -> memSys
    -> Word16
    -> Word16
bar :: ( MemorySystem memSys Word16 Word8) =>
    -> memSys
    -> Word16
    -> Word8
bar mem pc = ...
  -- bar calls foo -> rigid type variable error...

これにより、ghc で多くの固定型変数エラーが発生します。

メモリ インターフェイスのファミリを適切に表現できる (型クラスまたはファミリを介して作用する) ように、MemorySystemポリモーフィズムの「正しい型」につながるa を表現するより良い方法はありますか?memInternals

4

2 に答える 2

1

私のコメントを拡張するには、関連付けられた型ファミリを使用してみてください。しかし、あなたの現在のユースケースは、型クラスではなくデータ型によってうまく機能しているようです:

{-# LANGUAGE TypeFamilies, RankNTypes #-}
import Data.Vector.Unboxed

class MemorySystem memInternals where
  type AddrType memInternals
  type WordType memInternals

  mfetch :: memInternals
         -> AddrType memInternals
         -> AddrType wordType

  mfetchN :: Unbox wordType
          => memInternals
          -> AddrType memInternals
          -> Int
          -> Vector wordType

-- The record type may be more flexible and appropriate here
data MemorySystem addrType wordType = MemorySystem {
    mfetch :: addrType -> wordType
  , mfetchN :: Unbox wordType => addrType -> Int -> Vector wordType
  }

型クラスには、型パラメーターmemInternalsを最初の引数として 1 回だけ取る関数しかないことがわかりますか? これはレコードアプローチと同等のようです。

于 2012-12-14T12:02:42.657 に答える
0

少なくとも懸念事項を適切に分離するためには、記録アプローチが最も効果的です。これが私にとってうまくいくものです:

data (Unbox wordType) => MemorySystem addrType wordType memSys =
  MemorySystem
  { _mfetch :: addrType -> wordType
  , _ mfetchN :: addrType -> Int -> Vector wordType
  , _memInternals = memSys
  }

(とmemInternalsからアクセスできることに注意してください。したがって、これら 2 つの関数のパラメーターとして複製する必要はありません。) 次に、 と を使用して、このレコードのレンズを作成できます。次のような型を定義することもできます。mfetchmfetchNControl.LensmakeLenses

import Data.Word
import Data.Int

type Z80addr = Word16
type Z80word = Word8
type Z80memory memConfig = MemorySystem Z80addr Z80word memConfig

これにより、ポリモーフィック メモリ構成が可能になります。提案をしてくれた Chris に感謝します。型ファミリの観点から考えるということわざの軸になぜ私が巻き込まれたのかわかりません。

于 2012-12-14T19:21:55.827 に答える