Какой тип выбран для полиморфного выражения при печати?
Какой тип return "abc"
когда напечатано в ghci?
Суть вопроса в том, что в монаде она полиморфна:
ghci> :t return "abc"
return "abc" :: (Monad m) => m [Char]
и то, что печатается, зависит от того, какая монада выбрана:
ghci> return "abc" :: Maybe String
Just "abc"
ghci> return "abc" :: [] String
["abc"]
но вот что на самом деле напечатано:
ghci> return "abc"
"abc"
2 ответа
Когда вы вводите выражение expr
в GHCi происходят следующие вещи:
- Выражение проверяется типом. Если есть ошибка, GHCi сообщает об ошибке и сдается.
- В противном случае, скажем
expr
найдено, чтобы иметь типt
; GHC пытается соответствоватьt
противIO a
, - Если это удается, то он выполняет что-то вроде
it <- expr
тогда, еслиa
это примерShow
и не()
он выполняетprint it
, - Если это не удается, и
t
сам по себе является примеромShow
GHCi делает что-то вродеlet it = expr
а потомprint it
, - В противном случае это жалуется.
По сути, в GHCi вам нужен способ как выполнить действия ввода-вывода, так и получить возвращаемые значения, а также поиграться с чистыми значениями и посмотреть, что вы получите. Вот почему GHCi ведет себя так, как он делает: если кажется, что вы используете действие ввода-вывода, GHCi сделает это, и затем, если это действие имеет результат, который можно показать и интересный (т.е. не ()
) затем он показывает результат для вас. Если он не может показать вам результат, то это не имеет большого значения, потому что вы, вероятно, просто хотели запустить IO-действие; если бы вы хотели получить результат, вы бы назвали его <-
, С другой стороны, если вам кажется, что ваше выражение не является действием ввода-вывода, GHCi рассчитывает его и показывает вам, а если его невозможно отобразить, то GHCi не может сделать ничего полезного (на этот раз никаких побочных эффектов) так жалуется.
В этом случае, return "abc"
проверки типов как IO String
, а также String
это пример Show
так что GHCi делает что-то вроде
it <- return "abc"
print it
что по законам монады точно так же, как просто делать
print "abc"
отсюда и результат.
У Haskell есть немного озадачивающий набор правил для определения типов выражений, включающих числа; вы можете увидеть раздел отчета о неоднозначных типах и экземплярах по умолчанию. Так что ответ на общий вопрос сложен. Но в GHCi, если вы введете выражение e, вы можете положиться на следующие правила:
Если выражение е можно напечатать как
IO T
для какого-то типаT
, и еслиT
имеетShow
Например, GHCi запустит вычисление и выведет полученное значение типаT
, Вот что происходит в вашем третьем примере.Если выражение e * не может быть набрано в
IO
монада, тогда вступают в силу правила экземпляра по умолчанию, и GHCi выберет тип в соответствии с этими правилами. Если тип имеетShow
Экземпляр GHCi затем распечатаетshow
эл. Вот что происходит в первых двух примерах:Maybe String
а также[String]
являются чистыми ценностями сShow
экземпляров.Если тип е не имеет
Show
Например, тогда GHCi будет жаловаться. Это произойдет, если вы введете выражение вродеflip take
,