2013-05-28 15 views
13

Jestem nowy w Haskell i mam problem z funkcją interact. To jest mój przykładowy program:Funkcja interakcji Haskell

main :: IO() 
main = interact inputLength 

inputLength :: String -> String 
inputLength input = show $ length input 

To kompiluje ale podczas uruchamiania nie drukuje wyjście - tylko drukuje ciąg znaków, który jest przekazywany do niej i przechodzi do następnego wiersza. Kiedy przechodzą interact inny String -> String funkcję tak:

upperCase :: String -> String 
upperCase input = map toUpper input 

działa ok i drukuje argument na wielkie litery, jak oczekiwano - więc co jest nie tak z pierwszej funkcji?

+1

myślę 'interact' nadal jest piękny sposób pisania programów wiersza polecenia, które mają współpracować z potokami. W przypadku 'IO' mam ochotę napisać niepołączalne programy przeznaczone wyłącznie dla użytkowników. – luqui

Odpowiedz

32

interact :: String -> String wykonuje ciąg zawierający wszystko wejście i zwraca ciąg znaków zawierający wszystkie wyjściu. Powodem, dla którego widzisz wyjście po naciśnięciu klawisza Enter z interact (map toUpper), jest to, że map toUpper działa leniwie - może zacząć podawać dane wyjściowe, zanim znane będzie całe wejście. Odnalezienie długości łańcucha nie jest takie - cały ciąg musi być znany, zanim będzie można wyprodukować jakiekolwiek wyjście.

Musisz albo zasygnalizować EOF, aby powiedzieć, że skończyłeś wprowadzanie danych wejściowych (w konsoli, to jest Control-D na systemach Unix/Mac, myślę, że to Control-Z na Windows), to da ci długość. Albo można znaleźć długość każdej linii, mówiąc tak:

interact (unlines . map (show . length) . lines) 

To zawsze będzie leniwy w każdej linii, więc wiesz, że możesz dostać jedno wyjście po każdym wejściu.

Od działając na linii jest taki wspólny wzór, chciałbym zdefiniować niewiele funkcji pomocnika:

eachLine :: (String -> String) -> (String -> String) 
eachLine f = unlines . map f . lines 

Następnie można zrobić:

main = interact (eachLine inputLength)