输入类。家庭和多态性

时间:2012-12-13 19:49:13

标签: haskell polymorphism ghc emulation

我正在尝试编写一个相当简单的处理器模拟器,并试图将实际处理器与其内存接口分开。例如,旧的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是一种类型,它实现了由类型类函数部分指定的内存系统的接口。

在允许addrType为多态的同时限制wordTypememInterals的最佳方式是什么,即允许memInternals表示不同的内存配置。我发现自己在上下文中添加了上下文:

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中多态性的“正确类型”的memInternals,以便可以正确表示一系列内存接口(并通过类型进行操作)班级或家庭)?

2 个答案:

答案 0 :(得分: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 :(得分:0)

记录方法确实最有效,至少是为了正确分离关注点。这对我有用:

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

(请注意memInternals可以在mfetchmfetchN内访问,因此无需将其复制为这两个功能的参数。)然后可以创建镜头此记录,例如,使用Control.LensmakeLenses。它还允许定义类型:

import Data.Word
import Data.Int

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

允许多态内存配置。非常感谢克里斯提出的建议 - 我不确定为什么我会在类型系列方面围绕着众所周知的轴思考。