2013-02-01 33 views
32

Tôi mới dùng Haskell và tôi đang đấu tranh với việc gỡ lỗi mã của mình. Sửa lỗi dẫn đến các lỗi khác ...Không có trường hợp nào cho (Phân số Int) phát sinh từ việc sử dụng `/ '

Đây là mã của tôi.

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' 

Tôi hiện đang nhận được hai lỗi mà tôi đã viết trong nhận xét. Nếu bạn biết mã của tôi có gì sai, vui lòng chia sẻ ý tưởng của bạn và tiết kiệm thời gian của tôi ...

Cảm ơn bạn rất nhiều.

+0

Ý của bạn là 'Số (div a b)' hoặc phiên bản infix của nó? –

Trả lời

52
-- No instance for (Fractional Int) arising from a use of `/' 

Có lẽ đó là đến từ dòng này chứ không phải là một với nhận xét của bạn:

prim Div [Number a, Number b] = Number (a/b) 

abInt s. Toán tử phân chia là (/) :: Fractional a => a -> a -> a (bạn có thể tìm hiểu điều đó bằng cách kích hoạt ghci và nhập :t (/) hoặc theo số looking it up on Hoogle).

Nếu bạn chưa nhìn thấy loại như Fractional a => a -> a -> a, bạn nên đọc này thành hai phần:

  1. Bối cảnh Fractional a
  2. Loại a -> a -> a

Đây là giống như một thường xuyên a -> a -> a loại, vì vậy phải mất hai đối số của một số loại và cung cấp cho bạn kết quả của cùng một loại.Sự khác biệt duy nhất khi thêm ngữ cảnh Fractional a là loại được sử dụng cho a phải là một phiên bản của loại lớp Fractional; nó không phải là miễn phí để vượt qua bất kỳ loại nào bạn thích.

Nếu bạn chưa học về các lớp loại nhưng đừng lo lắng. Chúng khá dễ nắm bắt, nhưng không phải cái gì bạn nên nhìn sâu khi bạn mới bắt đầu; bạn sẽ nhận được chúng sau này.

Int không phải là thành viên của lớp loại Fractional, vì vậy nhà cung cấp / không hoạt động trên Int s.

Lý do là phân chia toán học thông thường không hoạt động trên các số nguyên với loại này; 3/2 sẽ phải cung cấp 1.5, trong trường hợp này không phù hợp với loại Int -> Int -> Int hoặc cung cấp 1 hoặc 2, trong trường hợp đó, đó không phải là bộ phận toán chính xác. Có chức năng div để triển khai integer division, có thể sử dụng được như a `div` b trong ký pháp infix.

-- Couldn't match expected type `Exp' with actual type `Value' 

Thư này là về các loại của riêng bạn, trong một biểu thức bạn đã viết. Và thông báo lỗi đầy đủ thực tế sẽ cho bạn thêm bối cảnh về phần nào của biểu thức chứa lỗi. Chỉ cần làm theo nó thông qua từ trên xuống, kiểm tra các loại của bản thân và lỗi rất nhanh chóng nhảy ra ngoài bạn.

Trong trường hợp này, bạn có thể ở đây:

Let [("x", (Literal (Number 2)))] (prim Add [(Variable "x"), (Variable "y")]) 

Let cần hai đối số, một [(String, Exp)] và một Exp. Danh sách là tốt, nhưng đối số thứ hai là (prim Add [(Variable "x"), (Variable "y")]). Thậm chí không cần đào sâu vào cấu trúc con để xem nó có chính xác không, prim có loại Op -> [Value] -> Value, vì vậy không có cách nào nó sẽ cung cấp cho bạn Exp.

Cách khắc phục tùy thuộc vào bạn; có vẻ như bạn cần một chút của một refactor trên toàn bộ biểu hiện/giá trị khác biệt. prim cung cấp cho bạn Value, bạn chỉ cần áp dụng gói trong một số Literal để giúp bạn vượt qua lỗi loại mà bạn nhận được, nhưng sau đó bạn gặp phải sự cố prim nên dùng Op[Value], nhưng dường như bạn có cho nó một Op[Exp] (có chứa các biến). Tôi nghĩ bạn cần phải suy nghĩ về sự khác biệt giữa việc sử dụng prim để tính toán kết quả của một ứng dụng nguyên thủy, sử dụng hàm tạo Primitive của Exp đến đại diện cho ứng dụng nguyên thủy và sử dụng eval để đánh giá (trong môi trường) một biểu thức tùy ý (có thể chứa một số ứng dụng nguyên thủy) cho một giá trị.

+0

oops, xấu của tôi. Tôi đặt bình luận sai dòng. – Nayana

+0

Cảm ơn bạn rất nhiều vì đã dành thời gian trả lời câu hỏi của tôi. – Nayana

+0

Tôi xin lỗi, nhưng điều này "(/) :: Fractional a => a -> a -> a" nghĩa là gì? Nó có nghĩa là phải mất một và một là một tham số và trả về một, phải không? nhưng có nghĩa là gì? Làm thế nào để tôi biết thực tế là Int không phải là một thành viên của lớp Fractional loại từ đó? – Nayana

19

Sự cố bạn gặp phải là Haskell có các hàm khác nhau cho số nguyên và phân số 'phân số'. Phân chia bộ tách số nguyên, phân chia phân đoạn thì không. Vì vậy, thay vì

prim Div [Number a, Number b] = Number (a/b) 

bạn muốn làm

prim Div [Number a, Number b] = Number (a `div` b) 

gì được thông báo lỗi thực sự có nghĩa là chức năng (/) là một phần của lớp Fractional. Đây là cơ bản một giao diện mà các loại khác nhau có thể thực hiện. Để có được thông tin về nó cháy lên ghci và làm

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' 

Đầu tiên cung cấp cho bạn thông tin về chức năng (/): nó sẽ cho bạn biết rằng nó là trong lớp Fractional. Sau đó, khi bạn :i Int nó hiển thị cho bạn tất cả các phiên bản cho Int. Lưu ý rằng Int không phải là phiên bản của Fractional để bạn không thể sử dụng (/) với Int.

Một mẹo: Các backticks (`) biến một hàm thành một nhà điều hành ghi rất

a `div` b 

cũng giống như

div a b 
+0

Cảm ơn bạn rất nhiều, bạn có ý tưởng về lỗi thứ hai không? – Nayana

+0

Vâng, Ben đã nhanh hơn ... – Paul

+0

'div' nhà điều hành woks cho tôi –

Các vấn đề liên quan