2016-05-03 4 views
3

Я наткнулся на поведение, которое я не могу объяснить в Haskell. Я пытаюсь сохранить полиморфную функцию в типе записи, которую я хочу использовать в ReaderT Monad. Когда я получаю свою функцию с asks, компилятор не распознает ее как полиморфную и, похоже, фиксирует тип при первом возникновении функции. Я создал минимальный пример в GHCI:Полиморфные функции в типах записей Haskell

{-# LANGUAGE Rank2Types    #-} 

data Test = Test {f :: (forall a. a -> a)} 

runReaderT (asks f 
      >>= \f -> (liftIO . putStrLn $ show (f 2 :: Int)) 
        >> (liftIO . putStrLn $ show (f "hello")) 
      ) (Test id) 

При попытке запуска этого я получаю:

Couldn't match expected type ‘Int’ with actual type ‘[Char]’ 
In the first argument of ‘f’, namely ‘"hello"’ 
In the first argument of ‘show’, namely ‘(f "hello")’ 
In the second argument of ‘($)’, namely ‘show (f "hello")’ 

Однако следующий код работает:

runReaderT (ask 
      >>= \(Test f) -> (liftIO . putStrLn $ show (f 2 :: Int))  
          >> (liftIO . putStrLn $ show (f "hello")) 
      ) (Test id) 

Так это что-то специальный с asks? Я благодарен за любые советы по этому поводу.

+0

Я предполагаю, что он должен делать с 'f' появляется после \ если я не ошибаюсь, аргументы лямбда-прежнему мономорфным если вам в противном случае. – Ingo

+1

Только хедз-ап: Rank2Types - это устаревшее расширение, наложенное на RankNTypes. (И RankNTypes просто позволяет вам писать 'forall'. Нет вывода более высокого ранга в GHC, так как подробности ответа Ingo.) – hao

ответ

4

Последний раз, когда я проверил, GHC не смог вывести более высокие типы рангов. Таким образом, если у вас есть

\f -> ... f x .... f y 

f никогда не может быть полиморфными.

Существует только два места, где тип некоторой переменной настолько очевиден, что вывод типа распознает более высокий тип ранга: в шаблонах, которые объявляют более высокие поля ранга и в LHS аннотированных функций.

Он также должен работать, чтобы дать тип явно, как в

\(f :: forall a.a -> a) -> .... f x ... f y 
+0

Спасибо за быстрый ответ! Это объясняет это. Таким образом, совпадение на \ (Test f) -> является первым случаем, о котором вы упоминаете, не так ли? –

+0

Именно поэтому это и сработало. – Ingo

Смежные вопросы