Próbuję nauczyć się pisać programy Haskella. Nie mogę odczytać wejścia n wierszy.

Wejście jest

N

A b (<----- n razy)

Gdzie n, a, b to liczby.

Próbowałem

input = []

readString 0 = return()
readString n =
 do
  z <- getLine
  z:input
  readString (n-1)

main = do
 n <- getLine
 readString n

Co powoduje błędy. Jak poprawnie zapętlić odczyt w Haskell?

1
kaiya 3 listopad 2018, 14:52

1 odpowiedź

Najlepsza odpowiedź

Haskell jest niezmienny: kiedy już napiszesz

input = []

Wtedy input jest [] na wieki wieków, amen. Możesz użyć tej samej techniki, której użyłeś do uzyskania „zmieniającej się” wartości n, aby uzyskać „zmieniającą się” wartość input, czyli przekazać ją jako argument do readString:

readString 0 input = return input
readString n input = do
  z <- getLine
  readString (n-1) (z:input)

Jeśli to zrobisz, odkryjesz, że linie, które wprowadzisz, są umieszczane w input, zaczynając od końca - więc wychodzą w odwrotnej kolejności! (Gdyby Twój fragment kodu zadziałał, również zachowywałby się w ten sposób.) Jednym z łatwych rozwiązań byłaby zmiana przypadku podstawowego:

readString 0 input = return (reverse input)

Bardziej idiomatycznym rozwiązaniem byłoby całkowite wyeliminowanie argumentu, po prostu zwracanie rzeczy we właściwej kolejności:

readString 0 = return []
readString n = do
  z <- getLine
  zs <- readString (n-1)
  return (z:zs)

Gdy oswoisz się ze standardową biblioteką, możesz najpierw przejść do:

readString 0 = return []
readString n = liftA2 (:) getLine (readString (n-1))

A następnie do całkowitego pominięcia definicji readString na rzecz przepisania main:

main = do
  n <- readLn
  replicateM n getLine
7
Daniel Wagner 3 listopad 2018, 15:50