Ответ 1
Это невозможно. Бесконечные типы (которые не являются типами данных) явно запрещены в Haskell, и легко создать код, который потребует их, и, следовательно, приведет к ошибке (например, попробуйте let foo = (42, foo) in foo
).
Вы можете, конечно, создать их с помощью newtype
и data
, как и вы, но тогда вы должны явно переносить и разворачивать значения внутри и вне конструкторов.
Это явное дизайнерское решение: с бесконечными типами многие явно неправильные выражения, которые мы хотели бы откомпилировать компилятором, должны быть разрешены, и, поскольку многие другие программы будут разрешены, многие ранее не однозначно типизированные программы становятся двунаправленными, 1 требующими явных аннотаций типа. Итак, сделаем компромисс: вам нужно четко указать на довольно редкое использование бесконечных типов взамен для получения большей помощи от системы типов, чем мы в противном случае.
Тем не менее, есть способ определить что-то похожее на вашу функцию eat
, используя классы типов, но она не может остановиться только тогда, когда вы дадите ей 3: дал ли вам это 3 или нет. определяется во время выполнения, и типы решаются во время компиляции. Однако здесь перегруженное значение, которое может быть как Integer
, так и функцией, которая просто поглощает свой аргумент:
class Eat a where
eat :: a
instance Eat Integer where
eat = 3
instance (Eat r) => Eat (a -> r) where
eat _ = eat
Уловка заключается в том, что вам нужно точно указать типы, когда вы его используете:
*Main> eat 1 foldr ()
<interactive>:6:1:
Ambiguous type variable `t0' in the constraint:
(Eat t0) arising from a use of `eat'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: eat 1 foldr ()
In an equation for `it': it = eat 1 foldr ()
*Main> eat 1 foldr () :: Integer
3
Это потому, что eat 1 foldr ()
может быть Integer
, но также может быть другой функцией, так же, как мы использовали eat 1
и eat 1 foldr
как функции в одном выражении. Опять же, мы получаем гибкую типизацию, но должны явно указывать типы, которые мы хотим взамен.
1 Подумайте о перегрузке текстового класса, например, о перегруженных числовых литералах (42
может быть любым типом, который является экземпляром Num
).