我是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'
我现在收到两条错误,我在评论中写道。 如果您知道我的代码有什么问题,请分享您的想法并节省我的时间......
非常感谢。
答案 0 :(得分:59)
-- 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
的类型,那么您应该分两部分阅读:
Fractional a
a -> a -> a
这就像常规a -> a -> a
类型一样,因此它需要两种类型的参数,并返回相同类型的结果。添加Fractional a
上下文的唯一区别是用于a
的类型必须是Fractional
类型类的实例;它不是任意类型的自由范围。
如果您还没有了解类型类,请不要担心。它们很容易掌握,但是当你刚刚开始时,你不应该深入研究它们;你以后会去找他们。
Int
不是Fractional
类型类的成员,因此/
运算符不适用于Int
。
原因是常规数学除法不对这种类型的整数起作用; 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
中应用换行即可超越您所遇到的类型错误,但是您遇到{{1}的问题应该使用prim
和Op
,但您似乎已经为其提供了[Value]
和Op
(包含变量)。我认为您需要考虑使用[Exp]
来计算基本应用程序的结果之间的区别,使用prim
的{{1}}构造函数来表示基元应用程序,并使用Primitive
来评估(在一个环境中)一个值的任意表达式(可能包含几个原始应用程序)。
答案 1 :(得分:24)
你遇到的问题是Haskell对整数和&#39;分数&#39;有不同的函数。师。整数除法截断,小数除法不。而不是
prim Div [Number a, Number b] = Number (a / b)
你想做什么
prim Div [Number a, Number b] = Number (a `div` b)
错误消息的实际含义是函数(/)
是Fractional
类的一部分。这基本上是不同类型可以实现的接口。要获取有关它的信息,请启动ghci并执行
Prelude> :i (/)
class Num a => Fractional a where
(/) :: a -> a -> a
...
-- Defined in `GHC.Real'
infixl 7 /
Prelude> :i Int
data Int = GHC.Types.I# GHC.Prim.Int# -- Defined in `GHC.Types'
instance Bounded Int -- Defined in `GHC.Enum'
instance Enum Int -- Defined in `GHC.Enum'
instance Eq Int -- Defined in `GHC.Classes'
instance Integral Int -- Defined in `GHC.Real'
instance Num Int -- Defined in `GHC.Num'
instance Ord Int -- Defined in `GHC.Classes'
instance Read Int -- Defined in `GHC.Read'
instance Real Int -- Defined in `GHC.Real'
instance Show Int -- Defined in `GHC.Show'
第一个为您提供有关函数(/)
的信息:它告诉您它在类Fractional
中。然后当您:i Int
时,它会显示Int
的所有实例。请注意,Int
不是Fractional
的实例,因此您无法将(/)
与Int
一起使用。
另一个提示:反引号(`)将函数转换为中缀运算符,所以
a `div` b
与
相同div a b