我是 Haskell 新手,我正在努力调试我的代码。 修复一个错误会导致其他错误...
这是我的代码。
import Data.Maybe
data Op = Add | Sub | Mul | Div | And | Or | Not | Eq | Less | Great
deriving (Eq, Show)
data Exp = Literal Value
| Primitive Op [Exp]
| Variable String
| If Exp Exp Exp
| Let [(String, Exp)] Exp
deriving (Show, Eq)
data Value = Number Int
| Bool Bool
| String String
deriving (Eq, Show)
type Env = [(String, Value)]
eval :: Env -> Exp -> Value
eval e (Literal v) = v
eval e (Variable x) = fromJust (lookup x e) --22
prim :: Op -> [Value] -> Value
prim Add [Number a, Number b] = Number (a + b)
prim And [Bool a, Bool b] = Bool (a && b)
prim Sub [Number a, Nuamber b] = Number (a - b) -- No instance for (Fractional Int) arising from a use of `/'
prim Mul [Number a, Number b] = Number (a * b)
prim Div [Number a, Number b] = Number (a / b)
prim Or [Bool a, Bool b] = Bool (a || b)
prim Not [Bool a] = Bool (not a)
prim Eq [Number a, Number b] = Bool (a == b)
prim Eq [String a, String b] = Bool (a == b)
prim Less [Number a, Number b] = Bool (a < b)
prim Less [String a, String b] = Bool (a < b)
prim Great [Number a, Number b] = Bool (a > b)
prim Great [String a, String b] = Bool (a > b) --37
main = do
eval [("y", (Number 40))] (Let [("x", (Literal (Number 2)))] (prim Add [(Variable "x"), (Variable "y")])) -- Couldn't match expected type `Exp' with actual type `Value'
我现在收到两个错误,这是我在评论中写的。 如果您知道我的代码有什么问题,请分享您的想法并节省我的时间...
非常感谢。
最佳答案
-- No instance for (Fractional Int) arising from a use of `/'
这可能是来自这一行,而不是您的评论:
prim Div [Number a, Number b] = Number (a / b)
a
和 b
是 Int
。除法运算符是 (/)::Fractional a => a -> a -> a
(您可以通过启动 ghci 并输入 :t (/)
来找到它>,或通过 looking it up on Hoogle )。
如果您还没有见过像 Fractional a => a -> a -> a
这样的类型,您应该分两部分阅读:
- 上下文
小数 a
- 类型
a -> a -> a
这就像常规的 a -> a -> a
类型一样,因此它需要某种类型的两个参数并返回相同类型的结果。添加 Fractional a
上下文的唯一区别是用于 a
的类型必须是 Fractional
类型类的实例;它不能随意选择您喜欢的任何类型。
如果您还没有了解类型类,请不要担心。它们很容易掌握,但在刚开始时不应该深入研究;您稍后会找到它们。
Int
不是 Fractional
类型类的成员,因此 /
运算符不适用于 Int
s.
原因是常规数学除法不适用于这种类型的整数; 3/2
必须给出 1.5
,在这种情况下它不适合类型 Int -> Int -> Int
,或者给出 1
或 2
,在这种情况下,它不是正确的数学除法。有一个函数div
用于实现integer division ,可以像中缀表示法中的 a `div` b
一样使用。
-- Couldn't match expected type `Exp' with actual type `Value'
这条消息是关于您自己的类型,在您编写的单个表达式中。实际的完整错误消息将为您提供有关表达式的哪一部分包含错误的更多上下文。只要从上到下遵循它,自己检查事物的类型,错误很快就会跳出来。
在这种情况下,您将到达这里:
Let [("x", (Literal (Number 2)))] (prim Add [(Variable "x"), (Variable "y")])
Let
需要两个参数,一个 [(String, Exp)]
和一个 Exp
。该列表很好,但第二个参数是 (prim Add [(Variable "x"), (Variable "y")])
。甚至没有深入研究它的子结构来看看它是否正确, prim
的类型是 Op -> [Value] -> Value
,所以它不可能给你Exp
。
如何解决这个问题取决于你;看起来您需要对整个表达式/值区别进行一些重构。 prim
为您提供一个 Value
,您可以简单地将其应用到 Literal
中以帮助您克服所遇到的类型错误,但是随后您遇到了 prim
应该采用 Op
和 [Value]
的问题,但您似乎给了它一个 Op
和 [Exp]
(包含变量)。我认为您需要考虑使用 prim
计算原始应用程序的结果、使用 Exp
的 Primitive
构造函数与 Exp
之间的区别em>代表一个原始应用程序,并使用eval
将(在环境中)任意表达式(可能包含多个原始应用程序)计算为一个值。
关于haskell - 没有因使用 `/' 而产生的 (Fractional Int) 实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14656762/