【问题标题】:Implementing instance of Read typeclass in haskell在haskell中实现Read typeclass的实例
【发布时间】:2017-08-19 15:14:04
【问题描述】:

我一直在玩一些归纳类型(定义的自然数和对它们的算术运算),但我无法让 Haskell 读取函数工作。

这是我的代码:

data Natural = Zero | Succ Natural
    deriving (Eq, Ord)

instance Enum Natural where
    pred Zero = undefined
    pred (Succ x) = x

    succ x = Succ x

    toEnum 0 = Zero
    toEnum x = Succ (toEnum (x - 1))

    fromEnum Zero = 0
    fromEnum (Succ x) = fromEnum x + 1

instance Num Natural where
    (+) x Zero = x
    (+) x (Succ y) = Succ (x + y)

    (-) Zero (Succ x) = undefined
    (-) x Zero = x
    (-) (Succ x) (Succ y) = x - y

    (*) x Zero = Zero
    (*) x (Succ y) = x * y + x

    abs x = x

    signum Zero = Zero
    signum (Succ x) = Succ Zero

    fromInteger 0 = Zero
    fromInteger x = Succ (fromInteger (x - 1))

instance Show Natural where
    show x = show $ fromEnum x

-- Not working!

instance Read Natural where
    readsPrec x = fromInteger $ (read x) :: Integer

我希望这个表达式有效: naturalNumber = read someStringWithInteger :: Natural,所以我不能只派生 Read 类型类。

我尝试过使用readsPrecreadPrec,但我只收到不匹配的类型错误。

如何实现 Read 类型类的实例?

【问题讨论】:

  • “我试过使用 readsPrec 和 readPrec,但我只得到不匹配的类型错误。” - 这是正确的方法。您应该包括您的类型错误。 readPrec = fmap fromInteger . readPrec 应该可以工作。 (除此之外:show $ fromEnum x 会为不适合 Int 的自然生成错误。你应该实现 Integral Natural 然后编写 show $ toInteger x

标签: haskell types typeclass induction


【解决方案1】:

您的函数类型错误。您的readsPrec 具有String -> Natural 类型,而您应该使用Int -> String -> [(Natural, String)]。但我们可以调整:

readsPrec p s = [(fromInteger i, s') | (i, s') <- readsPrec p s]

这使用了IntegerreadsPrec 函数。既然你想阅读Integers,那么为了方便使用它是很合适的。

出于对称原因,我建议您在 Show 实例中实现 showsPrec 而不是 show

【讨论】:

  • 我是 Haskell 的新手,你写的东西对我来说似乎很难。你能给我一些方法来实现showsPrec而不是show吗?
  • 与我实现readsPrec的方式相同,即showsPrec p n,其中nInt。您已经有办法从Natural 构建Int。不幸的是,由于ReadSShowSreadsPrecshowsPrec 都使用了稍微“混淆”的类型,但如果你把它们写出来,它会稍微容易一些。
  • 根据:i showsPrec:i ShowS,我得到了showsPrec 的完整签名:showsPrec :: Int -&gt; a -&gt; String -&gt; String。但是你写了showsPrec p n(只有2个参数)。我哪里错了?
  • 我不确定你是否已经知道这一点,但除了写addFive x = (+) 5 x,还可以写addFive = (+) 5。这称为部分应用。但是你可以明确写showsPrec p n s = showsPrec p (magic n) s(你必须用另一个函数替换magic)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多