2013-02-03 37 views
8

Tôi chỉ mới bắt đầu học haskell, và đó là một cách suy nghĩ khác nhiều so với những gì tôi đã quen thuộc (ngôn ngữ kiểu C).Cách haskell để chấp nhận người dùng nhập vào một người dùng nhập số lần?

Dù sao, đối với một vấn đề mà tôi đang làm việc, tôi cần nhận đầu vào của người dùng. Nó sẽ có dạng số

2 
10 
20 

chẳng hạn. Định dạng là dòng đầu tiên cho biết số lượng các dòng theo sau. Suy nghĩ đầu tiên của tôi là tôi sẽ đọc dòng đầu tiên, sau đó có một vòng lặp chạy số lần đó. Đây là Haskell mặc dù! Theo tôi biết, vòng lặp là không thể.

Suy nghĩ tiếp theo của tôi là tôi sẽ sử dụng dòng đầu vào đầu tiên để điền vào một danh sách với số n số khác theo sau. Tôi không có ý tưởng làm thế nào tôi sẽ làm điều này mặc dù. Tôi ở đây bởi vì tôi thậm chí không chắc chắn những gì tôi sẽ tìm kiếm để tìm ra nó.

Cảm ơn trước đã cho tôi biết cách haskell để thực hiện việc này. Thật khó khăn cho đến nay, nhưng tôi nghe những lời khen ngợi từ những người "giác ngộ" vì vậy tôi nghĩ rằng nó không thể làm tổn thương để học ngôn ngữ bản thân mình.

Dưới đây là mã sẽ chạy một lần tốt, nhưng cần phải chạy một lần cho từng dòng thứ hai thông qua n dòng theo dòng đầu tiên.

l n = (-1)^n/(2*(fromIntegral n)+1) 
a m = sum [l n | n <- [0..(m-1)]] 
main = 
    do b <- readLn 
     print (a b) 

(Ngoài ra, tôi rất thích nghe nếu có những cải tiến khác tôi có thể làm để mã của tôi, nhưng trong trường hợp cụ thể này, nó là dành cho một cuộc thi để giải quyết một vấn đề trong số ít nhất của các nhân vật càng tốt. Tôi không muốn cụ thể hơn trong trường hợp những người khác đang cố gắng tìm kiếm câu trả lời cho cùng một vấn đề.)

EDIT: Cảm ơn mọi câu trả lời. Cuối cùng tôi đã có một cái gì đó mà cư xử như thế nào tôi muốn nó. Tôi đặt mã cho điều đó dưới đây cho hậu thế. Đáng buồn thay, mặc dù nó đã vượt qua các trường hợp thử nghiệm với màu sắc bay, dữ liệu thực tế mà họ thử nghiệm trên nó là khác nhau, và tất cả những gì họ nói với tôi là tôi nhận được "câu trả lời sai". Mã này "hoạt động" nhưng không nhận được câu trả lời đúng.

import Control.Monad 
l n = (-1)^n/(2*(fromIntegral n)+1) 
a m = sum [l n | n <- [0..(m-1)]] 
main = 
    do b <- readLn 
     s <- replicateM b readLn 
     mapM_ print [a c | c <- s] 
+0

Có thể đó là lỗi làm tròn? Có thể thử sử dụng các số hữu tỉ cho mọi thứ rồi chuyển đổi sang phao ở phút cuối cùng: ('import Data.Ratio',' l :: Integer -> Rational' và 'mapM_ (print. RealToFrac)') – luqui

+1

Đó là loại lỗi làm tròn. Ngay cả sau khi tôi đã làm điều này nó đã sai. Vấn đề của tôi là tôi đã quá chính xác. Tôi đã đưa ra như 16 chữ số sau thập phân chính xác, nhưng họ chỉ muốn 15 chữ số. Có một cách haskell để làm điều này? Vấn đề này không phải là một cái gì đó bạn muốn chạy vào trong cuộc sống thực mặc dù. Hầu hết các công ty sẽ không bao giờ yêu cầu độ chính xác thấp hơn và ít ký tự nhất có thể (dẫn đến các tên biến 1 ký tự khủng khiếp này) – maccam912

+0

bạn không phải xây dựng danh sách chỉ để có vòng lặp: '' main = do {b <- readLn; replicateM_ b (do {c <- readLn; print (a c)})} ''. Hoặc các vòng lặp có thể được mã hóa trực tiếp với đệ quy: 'main = readLn >> = loop'; 'loop n | n <1 = return() | else = readLn >> = (in. a) >> vòng lặp (n-1) '. –

Trả lời

10

Trước hết, bạn có thể lặp lại tốt trong haskell. Lúc nào chả vậy. Bạn chỉ không có cấu trúc cú pháp cho nó, vì không cần chúng.

Hầu hết thời gian, các vòng chung mục đích chung được đưa vào thư viện. Trong trường hợp này, vòng lặp bạn cần có trong thư viện chuẩn, trong mô-đun Control.Monad. Nó được gọi là replicateM. Nó có chữ ký loại Monad m => Int -> m a -> m [a]. Để chuyên chữ ký này cho trường hợp của bạn, nó sẽ có loại Int -> IO Int -> IO [Int]. Đối số đầu tiên là số lần lặp. Thứ hai là hành động IO để chạy trên mỗi vòng lặp. Kết quả của hàm là một hành động IO tạo ra danh sách các đầu vào.

Vì vậy, nếu bạn thêm inputs <- replicateM b readLn vào khối của bạn, nó sẽ đặt một danh sách có tên inputs vào phạm vi có chứa các giá trị từ b dòng đầu vào theo sau đầu tiên. Sau đó, bạn có thể ánh xạ chức năng giải pháp của mình qua các dòng đó.

1

Bạn có thể tạo readInput n trong đó n là số dòng cần đọc. Các cuộc gọi này đệ quy trừ 1 từ n mỗi lần. Tôi cũng là một Haskell noob, vì vậy đây có thể không phải là cách tiếp cận tốt nhất. Nó vẫn nên làm việc, mặc dù.

6

Giải pháp của Carl sẽ hoạt động, nhưng nó hơi mờ.Nếu bạn muốn viết nó ra, bạn có thể làm một cái gì đó như thế này:

readLines :: Int -> IO [Int] 
readLines 0 = return [] 
readLines n = do 
    x <- fmap read getLine 
    rest <- readLines (n-1) 
    return $ x : rest 

readSomeNumberOfLines :: IO [Int] 
readSomeNumberOfLines = do 
    n <- fmap read getLine 
    readLines n 

Những gì bạn đang làm gì ở đây với readLines được bạn cần phải xác định các trường hợp cơ sở rõ ràng (để đọc 0 điều, chỉ cần đưa ra một sản phẩm nào danh sách) và trường hợp đệ quy (để đọc n điều, đọc một điều, sau đó đọc những thứ n-1 khác, sau đó kết hợp chúng lại với nhau).

2

Tôi không chắc chắn những gì chính xác bạn muốn làm, nhưng để đọc một số nguyên n và sau đó n dòng tiếp theo là số nguyên bạn có thể làm một cái gì đó như:

import Control.Monad 

-- read n, then sum integers read from the next n lines 
test = do n <- readLn 
      xs <- replicateM n readLn 
      return $ sum xs 

Các return $ sum xs ở cuối tất nhiên là không đáng kể - nếu không có ở đó, bạn cần một chữ ký kiểu chữ rõ ràng cho test.

Nếu bạn không hiểu bất kỳ chức năng nào trong số này, chỉ cần hoogle chúng.

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