Как GHCi выбирает экземпляр класса типа Monad для использования в полиморфных действиях?


Я новичок в Хаскелле, так что это может быть нубовский вопрос.

Когда я делаю return 10 >>= return GHCi показывает 10. Когда я проверяю тип return 10 с :t, он просто говорит return 10 :: (Monad m, Num a) => m a, и я делаю typeOf return 10, я получаю ошибку.

Но насколько я понимаю, Хаскелл должен был использовать конкретный экземпляр >>= для оценки return 10 >>= return, так какой экземпляр он использовал и как он решил, какой из них использовать?
1 3

1 ответ:

Это следует из идеи, что GHCi является чем-то вроде гигантского блока do IO. Всякий раз, когда вы вводите что-то, что является выражением, он сначала пытается увидеть, может ли тип результата быть специализирован на чем-то в форме IO a. Если это возможно, он выполняет действие IO и просто печатает результат. Только в противном случае он выводит результат самого выражения.

Чтобы заставить GHCi перейти к любой конкретной монаде, которую вы хотите, вы можете добавить аннотацию типа. Обратите внимание, как IO получает трактуется по-разному (и так же, как трактовалось бы выражение без всякой аннотации).

ghci> return 10 >>= return :: Maybe Int
Just 10
ghci> return 10 >>= return :: [Int]
[10]
ghci> return 10 >>= return :: IO Int
10

В стороне, есть совершенно другая проблема относительно того, какой экземпляр Num выбран, и это имеет все отношение к нарушению правил и ограничению мономорфизма.