2012-04-06 37 views
8

Hai chức năng sau đây rất giống nhau. Họ đọc từ một phần tử [String] n, hoặc [Int] hoặc [Float]. Làm thế nào tôi có thể yếu tố mã phổ biến ra? Tôi không biết bất kỳ cơ chế nào trong Haskell hỗ trợ các kiểu truyền đi như là các đối số.Vượt qua các loại làm đối số cho một hàm trong Haskell?

readInts n stream = foldl next ([], stream) [1..n] 
    where 
    next (lst, x:xs) _ = (lst ++ [v], xs) 
     where 
     v = read x :: Int 

readFloats n stream = foldl next ([], stream) [1..n] 
    where 
    next (lst, x:xs) _ = (lst ++ [v], xs) 
     where 
     v = read x :: Float 

Tôi ở cấp độ mới bắt đầu của Haskell, vì vậy mọi nhận xét trên mã của tôi đều được chào đón.

+2

Bạn không cần phải gấp đây, bạn có thể nhận được bởi với một bản đồ đơn giản. ví dụ. 'bản đồ đọc stream :: [Int]' Ngoài ra bạn có thể muốn xem xét lý do tại sao bạn muốn sử dụng foldr trong Haskell chứ không phải là foldl. –

+1

@EdwardKmett Cảm ơn đề xuất của bạn. Điều tôi thực sự muốn là chỉ đọc các phần tử n đầu tiên và trả về danh sách và phần còn lại của luồng. Tôi đã rất buồn ngủ ngày hôm qua, và không thể suy nghĩ được. Tôi nghĩ rằng bạn muốn nói rằng với foldr tôi có thể sử dụng constructor: trực tiếp phải không? Sau đó tôi viết lại nó như là '(bản đồ đọc firstn, phần còn lại) trong đó (firstn, rest) = splitAt n stream', khá giống với những gì bạn đề nghị. –

+0

Bạn không cần phải làm tổ 'where'; bạn có thể đặt 'next (lst, x: xs) _ = ...' và 'v = ...' trong các dòng liên tiếp. – sdcvvc

Trả lời

14

Haskell hỗ trợ mức độ đa hình cao. Đặc biệt

readAny n stream = foldl next ([], stream) [1..n] 
    where 
    next (lst, x:xs) _ = (lst ++ [v], xs) 
     where 
     v = read x 

có kiểu

readAny :: (Enum b, Num b, Read a) => b -> [String] -> ([a], [String]) 

do đó

readInts :: (Enum b, Num b, Read a) => [String] -> ([Int], [String]) 
readInts = readAny 

readFloats :: (Enum b, Num b, Read a) => [String] -> ([Float], [String]) 
readFloats = readAny 

bạn không cần phải chuyên các loại. Haskell sẽ tự động suy ra loại chung nhất có thể, và readAny ở đây sẽ làm những gì bạn muốn.

Không thể chuyển loại làm đối số trong Haskell. Hiếm khi bạn cần. Đối với những trường hợp đó, bạn cần mô phỏng hành vi bằng cách chuyển một giá trị với kiểu mong muốn.

Haskell có "đa hình kiểu trả về" vì vậy bạn thực sự không nên lo lắng về việc "chuyển loại" - tỷ lệ cược là các chức năng sẽ làm những gì bạn muốn mà không cần bạn nói.

+3

Trớ trêu thay, * đi qua loại * là một số cách thực hiện phụ thuộc vào những gì xảy ra đằng sau hậu trường, do đó câu hỏi không phải là quá xa ... – Ingo

+1

Nhiều triển khai không vượt quá loại như vượt qua một loại nhân chứng phù hợp cho các giá trị kiểu lớp. Một cái gì đó giống như 'id' không cần phải biết các loại đối số của nó ở tất cả (miễn là tất cả mọi thứ có cùng kích thước) –

+1

Đó là những gì tôi có ý nghĩa với * cách thực hiện phụ thuộc *. Nhưng * id *, không có ràng buộc, không được thông qua gì cả, tôi đoán vậy. Loại bảo đảm rằng id sẽ không làm bất cứ điều gì với đối số của nó mà sẽ cần thêm thông tin hơn chỉ là "đó là một số giá trị", nhưng điều này nên được ngụ ý. – Ingo

9

Về cơ bản những gì bạn muốn là không khai báo rõ ràng loại. Thay vào đó, trì hoãn việc khai báo loại và để cho công cụ suy luận tiếp quản cho bạn. Ngoài ra, tôi nghĩ bạn đang gấp nếp với bản đồ. Đây là cách tôi sẽ tiếp cận nó.

readList' :: Read a => [String] -> [a] 
readList' = map read 


ints = readList' ["1", "2"] :: [Int] -- [1, 2] 

floats = readList' ["1.0", "2.0"] :: [Float] -- [1.0, 2.0] 

Để đọc chỉ n thứ từ con suối, sử dụng take

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