Как напечатать многострочную строку с помощью `putStrLn`?
Я пишу очень простую программу на Haskell, которая запрашивает у пользователя имя, а затем отображает некоторый текст, основанный на этом имени. Я могу заставить программу работать, но я хотел бы отобразить ASCII-изображение кота, когда пользователь вводит имя моей кошки. Я хотел бы что-то такое, как
^ - ^
( . . )
=>;<=
/ \
| |
Мой подход "давайте просто посмотрим, сработает ли это" заключался в использовании putStrLn. Это не работает Что я могу сделать? Благодарю. Моя попытка
if name == "cat"
then putStrLn (" ^ - ^
( . . )
=>;<=
/ \
| |")
2 ответа
Ли спросил: "Как не putStrLn
работа?", и вы ответили:
if name == "cat"
then putStrLn (" ^ - ^
( . . )
=>;<=
/ \
| |")
Вы должны включить сообщения об ошибках. Поместив это в функцию верхнего уровня (test name = ...
) код не компилируется с:
so.hs:3:38: error:
lexical error in string/character literal at character '\n'
Это потому, что вы не можете иметь переводы строк в строковых литералах Haskell. Многострочные строки в Haskell требуют специального экранирования (обратная косая черта в начале и в конце каждой строки. У вас уже есть неэкранированная обратная косая черта в ascii art, которая должна была быть экранирована, поэтому мы исправим это тоже:
test name =
if name == "cat"
then putStrLn (" ^ - ^\n\
\ ( . . )\n\
\ =>;<=\n\
\ / \\\n\
\ | |")
Теперь мы получаем еще одну ошибку, потому что в Haskell if
операторы больше похожи на троичный оператор и поэтому требуют, чтобы ветвь else оставалась хорошо типизированной. Полученный код:
test name =
if name == "cat"
then putStrLn (" ^ - ^\n\
\ ( . . )\n\
\ =>;<=\n\
\ / \\\n\
\ | |")
else return ()
В качестве альтернативы вы можете использовать квази-кавычки для более симпатичных многострочных строк. Это требует string-qq
пакет и расширение языка квазиквот. Расширение имеет синтаксис [|<quoter name>|<string>|]
а пакет string-qq содержит квотер с именем s
для строк:
{-# LANGUAGE QuasiQuotes #-}
import Data.String.QQ
import Control.Monad (when)
test2 name =
when (name == "cat") $ putStrLn [s|
^ - ^
( . . )
=>;<=
/ \\
| ||]
Вот еще одна альтернатива, которую я иногда использую:
putStr $ unlines
[ " ^ - ^"
, " ( . . )"
, " =>;<="
, " / \\"
, " | |"
]
unlines
это стандартная функция, которая берет список строк и объединяет их, а также вставляет символы новой строки после каждой строки (включая последнюю - поэтому я и использовал putStr
вместо).
> unlines ["abc", "def", "ghi"]
"abc\ndef\nghi\n"