2012-03-04 28 views
5

Tôi đang sử dụng thực hiện này của maybeRead:Haskell: đọc một số (Integer hoặc Floating point)

maybeRead :: (Read a) => String -> Maybe a 
maybeRead = fmap fst . listToMaybe . filter (null . dropWhile isSpace . snd) . reads 

và riêng getNum chức năng của tôi mà nhắc đến khi nó được đầu vào hợp lệ:

getNum :: (Num a, Read a) => String -> IO a 
getNum s = do 
    putStr s 
    input <- fmap maybeRead getLine 
    if isNothing input 
     then getNum s 
     else return $ fromJust input 

Tuy nhiên nếu tôi nhập 5.2 thì nó coi đó là đầu vào kém — Tại sao? Có số lần xuất hiện là IntInteger trong mã của tôi. Tôi chỉ đang sử dụng Num, vì tôi muốn chấp nhận bất kỳ loại số nào.

Nếu tôi gọi nó rõ ràng là getNum "Enter a number: " :: IO Double thì nó hoạt động. Tôi có phải làm việc này không? Là hệ thống kiểu Haskell chỉ lừa tôi nghĩ tôi có thể làm điều này khi thực sự nó là không thể mà không gõ đầy đủ năng động? Nếu vậy thì tại sao mã của tôi thậm chí biên dịch; tại sao nó giả định số nguyên?

+2

Ghi chú phong cách nhỏ: Tốt hơn là sử dụng mẫu khớp với 'isNothing' và' fromJust', vì vậy biểu thức 'if' có thể được thay thế bằng' trường hợp đầu vào Không có gì -> getNum s; Chỉ cần x -> return x'. – hammar

+0

Cảm ơn, điều đó có vẻ tốt hơn rất nhiều. – mk12

Trả lời

13

Chức năng của bạn thực sự sẽ chấp nhận Integer, Float hoặc bất kỳ trường hợp nào khác Num. Tuy nhiên, loại nào nó chấp nhận và mở rộng cách phân tích cú pháp số String, không được xác định bởi đầu vào nó nhận được, được xác định bởi loại kết quả là dựa trên những gì bạn làm với nó.

Giả sử bạn sử dụng getNum và chuyển giá trị kết quả cho một thứ cần số Float; trong trường hợp đó, nó sẽ phân tích giá trị Float. Nếu bạn chuyển nó cho một cái gì đó cần một Integer thay vào đó, nó sẽ phân tích cú pháp đó.

Đối với lý do tại sao nó giả Integer, có một hệ thống "mặc định" với nhiều loại mơ hồ specified in the Haskell Report, và các quy tắc nói rằng một loại mơ hồ với một hạn chế Num nên mặc định Integer.

+0

Được rồi, vì vậy tôi đoán trong ví dụ của mình, tôi sẽ phải thêm ':: (Phân số a, Đọc a) => IO a' khi tôi gọi' getNum' để cho phép các số thập phân (và tôi không muốn chỉ định rõ ràng) float hoặc double). – mk12

+1

Có, nhưng lưu ý rằng việc thêm ràng buộc 'Fractional' sẽ giới hạn nó để chấp nhận * chỉ * các trường hợp của' Phân số', vì vậy bạn sẽ không thể sử dụng nó cho các loại khác theo cách đó. Hầu hết thời gian trong một chương trình thực tế bạn sẽ biết một loại cụ thể mà bạn cần, vì vậy thường không có lý do gì để hạn chế mọi thứ, ngoại trừ những thứ như thử nghiệm trong GHCi. –

+1

Tôi không thêm nó vào chức năng thực tế, tôi đã thêm nó như một chú thích kiểu khi tôi sử dụng hàm. Tôi không hoàn toàn chắc chắn tôi hiểu những gì bạn đang nói trong câu cuối cùng - không phải là ràng buộc typeclass phổ biến trong mã Haskell cho generalizing chức năng? – mk12