我是否正在为我的玩具语言评估员做准备?

时间:2017-05-01 02:23:08

标签: haskell

我试图为我的玩具语言编写评估员。我想要包括的一件事是Ints和Doubles。这是我最近的尝试:

{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
module Types where

import Prelude

data family Number n
data instance Number Integer = NumInt Integer deriving (Eq,Show)
-- data instance Number Double  = NumDouble Double deriving (Eq,Show)

data Expr a where
  BoolConst   :: Bool   -> Expr Bool
  NumConst    :: Number num -> Expr (Number num)

  Equals      :: Expr (Number num)  -> Expr (Number num) -> Expr Bool

class ChunkyNum a where
  equals :: a -> a -> Bool

-- more methods to be added

instance ChunkyNum (Number Integer) where
  equals a b = a == b

这是我的评估功能

{-# LANGUAGE GADTs #-}
module Eval where

import Types

eval :: Expr z -> z
eval (BoolConst b)     = b
eval (NumConst b)      = b

在ghci,我可以做到这一点。

*Main Eval Types> let five = NumConst (NumInt 5 :: Number Integer)
*Main Eval Types> let ten = NumConst (NumInt 10 :: Number Integer)
*Main Eval Types> eval five == eval ten
False

现在,我尝试在我的eval函数中做类似的事情

eval :: Expr z -> z
eval (BoolConst b)     = b
eval (NumConst b)      = b
eval (Equals a b)      = (eval a) `equals` (eval b)

然后,尝试编译:

~/projects/git/chunky/src/Eval.hs:12:26: error:
    • Could not deduce (ChunkyNum (Number num))
        arising from a use of ‘equals’
      from the context: z ~ Bool
        bound by a pattern with constructor:
                   Equals :: forall num.
                             Expr (Number num) -> Expr (Number num) ->    Expr Bool,
                 in an equation for ‘eval’
        at src/Eval.hs:12:7-16
•     In the expression: (eval a) `equals` (eval b)
      In an equation for ‘eval’:
           eval (Equals a b) = (eval a) `equals` (eval b)

我认为我走在正确的轨道上,我只需要向ghc提供更多信息。我是,如果是的话,下一步是什么。如果没有,我该如何解决这个问题?

Lazersmoke,您的建议有效,但我必须向Equals构造函数添加约束。这是在ghc的要求下,但我想知道它是否仍然是不好的做法。

Equals      :: (ChunkyNum num) => Expr (Number num)  -> Expr (Number num) -> Expr Bool

1 个答案:

答案 0 :(得分:2)

GHC告诉您,它无法知道每个Number num都会有ChunkyNum的实例。您可以通过将Number数据系列更改为ChunkyNum的关联数据系列来解决此问题:

class ChunkyNum a where
  data Number a :: *
  equals :: Number a -> Number a -> Bool

使用像

这样的实例
instance ChunkyNum Integer where
  data Number Integer = NumInt Integer
  equals (NumInt a) (NumInt b) = a == b

否则,您必须编写instance ChunkyNum (Number num) where,这对于独立(开放)数据系列是不可能的。

如果这些内容不适用于您的使用案例,请与我们联系。

Further Reading