Другой подход, который я бы выбрал, чтобы убедиться, что я получаю сигнатуру типа, ожидаемую для конкретного лямбда-выражения, избегая при этом :t
, - это использование сигнатур типов.
В этом случае x
неограниченно.
idFunction = \x -> x
Если мы хотим ограничиться определенным типом, мы можем аннотировать x
напрямую.(Для этого требуется :set -XScopedTypeVariables
в GHCi или {-# LANGUAGE ScopedTypeVariables #-}
в файле).
idFunction = \(x :: Int) -> x
или мы можем добавить сигнатуру типа
idFunction :: Int -> Int
idFunction = \x -> x
В вашем примере у вас есть только сигнатуры типов, но без функции тела.Давайте добавим несколько простых тел функций, чтобы мы могли что-то сделать с компилятором, затем мы попробуем добавить сигнатуру типа в c
, чтобы подтвердить наше убеждение о том, каким должен быть тип.Мы начнем с неверной подписи типа.
a :: Int -> Bool
a x = x > 0
b :: Bool -> String
b y = show y
c :: ((Bool -> Bool) -> (Bool -> Bool) -> t) -> t
c = \d -> d a b
Компилятор найдет некоторые ошибки в c
:
<interactive>:10:17: error:
• Couldn't match type ‘Bool’ with ‘Int’
Expected type: Bool -> Bool
Actual type: Int -> Bool
• In the first argument of ‘d’, namely ‘a’
In the expression: d a b
In the expression: \ d -> d a b
<interactive>:10:19: error:
• Couldn't match type ‘[Char]’ with ‘Bool’
Expected type: Bool -> Bool
Actual type: Bool -> String
• In the second argument of ‘d’, namely ‘b’
In the expression: d a b
In the expression: \ d -> d a b
Теперь, если мы дадим c
правильную подпись типа, тоскомпилирует
c :: ((Int -> Bool) -> (Bool -> String) -> t) -> t
c = \d -> d a b
Как правило, нет причин избегать :t
.Это очень хороший инструмент, когда вы работаете в GHCi, но когда вы создаете сложные функции в библиотеке, вам не обязательно иметь доступ к :t
, поэтому альтернативой является тестирование сигнатур разных типов и просмотр реакции компилятора..