Haskell 我正在寻找我的玩具语言评估器吗?

Haskell 我正在寻找我的玩具语言评估器吗?,haskell,Haskell,我正试图为我的玩具语言编写一个评估程序。我想包括的一件事是整数和双倍。以下是我的最新尝试: {-# LANGUAGE GADTs #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE FlexibleInstances #-} module Types where import Prelude data family Number n data instance Number Integer = NumInt Integer deriving (Eq,

我正试图为我的玩具语言编写一个评估程序。我想包括的一件事是整数和双倍。以下是我的最新尝试:

{-# 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
Equals      :: (ChunkyNum num) => Expr (Number num)  -> Expr (Number num) -> Expr Bool
这是我的求值函数

{-# LANGUAGE GADTs #-}
module Eval where

import Types

eval :: Expr z -> z
eval (BoolConst b)     = b
eval (NumConst b)      = b
eval :: Expr z -> z
eval (BoolConst b)     = b
eval (NumConst b)      = b
eval (Equals a b)      = (eval a) `equals` (eval b)
Equals      :: (ChunkyNum num) => Expr (Number num)  -> Expr (Number num) -> Expr Bool
在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
Equals      :: (ChunkyNum num) => Expr (Number num)  -> Expr (Number num) -> Expr Bool
现在,我尝试在eval函数中执行类似的操作

{-# LANGUAGE GADTs #-}
module Eval where

import Types

eval :: Expr z -> z
eval (BoolConst b)     = b
eval (NumConst b)      = b
eval :: Expr z -> z
eval (BoolConst b)     = b
eval (NumConst b)      = b
eval (Equals a b)      = (eval a) `equals` (eval b)
Equals      :: (ChunkyNum num) => Expr (Number num)  -> Expr (Number num) -> Expr Bool
然后,尝试编译:

~/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)
Equals      :: (ChunkyNum num) => Expr (Number num)  -> Expr (Number num) -> Expr Bool
我认为我的思路是正确的,我只需要向ghc提供更多信息。我是,如果是,下一步是什么。如果没有,我该如何着手解决这个问题

Equals      :: (ChunkyNum num) => Expr (Number num)  -> Expr (Number num) -> Expr Bool
Lazersmoke,你的建议奏效了,但我不得不给Equals构造函数添加一个约束。这是ghc的要求,但我不知道这是否仍然是一种不好的做法

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

GHC告诉您,它不可能知道每个
Number num
都有
ChunkyNum
的实例。您可以通过将
编号
数据族更改为
ChunkyNum
的关联数据族来解决此问题:

Equals      :: (ChunkyNum num) => Expr (Number num)  -> Expr (Number num) -> Expr Bool
class ChunkyNum a where
  data Number a :: *
  equals :: Number a -> Number a -> Bool
例如

Equals      :: (ChunkyNum num) => Expr (Number num)  -> Expr (Number num) -> Expr Bool
instance ChunkyNum Integer where
  data Number Integer = NumInt Integer
  equals (NumInt a) (NumInt b) = a == b
否则,您将不得不编写一个
实例ChunkyNum(Number num),其中
,这对于独立(开放)数据族是不可能的

Equals      :: (ChunkyNum num) => Expr (Number num)  -> Expr (Number num) -> Expr Bool
如果这些不适用于您的用例,请告诉我

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

GHC告诉您,它不可能知道每个
Number num
都有
ChunkyNum
的实例。您可以通过将
编号
数据族更改为
ChunkyNum
的关联数据族来解决此问题:

Equals      :: (ChunkyNum num) => Expr (Number num)  -> Expr (Number num) -> Expr Bool
class ChunkyNum a where
  data Number a :: *
  equals :: Number a -> Number a -> Bool
例如

Equals      :: (ChunkyNum num) => Expr (Number num)  -> Expr (Number num) -> Expr Bool
instance ChunkyNum Integer where
  data Number Integer = NumInt Integer
  equals (NumInt a) (NumInt b) = a == b
否则,您将不得不编写一个
实例ChunkyNum(Number num),其中
,这对于独立(开放)数据族是不可能的

Equals      :: (ChunkyNum num) => Expr (Number num)  -> Expr (Number num) -> Expr Bool
如果这些不适用于您的用例,请告诉我

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

这是正确的。无论如何,您只能在
ChunkyNum
s上执行
Equals
,因此该约束很有意义。如果你正在寻找设计改进,我会考虑你是否真的需要一个数据家族。您可以使用类型族,或者完全摆脱类型类,并对任何
Eq
uatable或
Num
ber进行操作。这是正确的。无论如何,您只能在
ChunkyNum
s上执行
Equals
,因此该约束很有意义。如果你正在寻找设计改进,我会考虑你是否真的需要一个数据家族。您可以使用一个类型族,或者完全摆脱类型类,对任何
Eq
uatable或
Num
ber进行操作。
Equals      :: (ChunkyNum num) => Expr (Number num)  -> Expr (Number num) -> Expr Bool