#haskell #types
#haskell #типы
Вопрос:
Я пишу оценщик для небольшого языка выражений, но я застрял на rec
конструкции.
Попытка определить функцию, которая позволяет узнать тип, который имеет параметр.
Это язык:
data Ty = Ty :-> Ty | INT deriving (Eq,Show)
infixr 9 :->
data Expr = Var Nm | Lam (Nm,Ty) Expr | App Expr Expr
| Val Int | Add Expr Expr | If Expr Expr Expr
| Let Nm Expr Expr
| Rec Expr deriving Show
type Nm = String
И это оценщик до сих пор:
type Te = [ (Nm, Ty) ]
type En = [ (Nm, Value) ]
ty :: Te -> Expr -> Ty
ty te (Var x) = lookup' x te
ty te (Lam (x,t) e) = t :-> t2
where
t2 = ty ((x,t):te) e
ty te (App e1 e2) =
case t1 of
t2' :-> t | t2==t2' -> t
| otherwise -> error $ show e1 show e2
_ -> error $ show "not a function type"
where
t1 = ty te e1
t2 = ty te e2
ty te (Val _) = INT
ty te (Add e1 e2) =
case (t1, t2) of
(INT, INT) -> INT
(INT, _ ) -> error $ show "is not INT type"
_ -> error $ show e1 "is not INT type"
where
t1 = ty te e1
t2 = ty te e2
ty te (If e e1 e0) =
case t of
INT | t1 == t0 -> t1
| otherwise -> error $ show "different type"
_ -> error $ show e "is not INT type"
where
t = ty te e
t1 = ty te e1
t0 = ty te e0
ty en (Let x e1 e2) = ty ((x,t2) : en) e2
where
t2 = ty en e1
ty te e = error $ show e "type inference is not defined yet"
lookup' x en = case lookup x en of
Nothing -> error (x " not defined")
Just v -> v
Например, тест типа let
:
t1 = Let "z" (Val 1) (Add (Var "z") (Val 2))
ty [] t1
ответ: INT
rec
выражение используется для определения рекурсивной функции
Это моя тестовая функция, которую я хочу оценить:
t2 = Rec (Lam ("f", INT :-> INT) . Lam ("i", INT) $
If (Var "i")
(Var "i" `Add` (App (Var "f") (Var "i" `Add` Val(-1))))
(Var "i")
)
ty [] t2
Я пытался сделать выражение:
ty en (Rec (Lam (x,_) e)) = v
where
v = ty ((x,v):en) e
Rec
пробовал тест типа like let
, но есть ошибка.
Комментарии:
1. Что это
Rec
значит? Рекурсивный?2.
rec
используется для определения рекурсивной функции. Я пересмотрел вопрос и переписал его!
Ответ №1:
Я уже реализовывал подобный код в прошлом, так что вам следует обратиться к нему. Вам не нужно обращать внимания на наличие лицензии (ЛИЦЕНЗИЯ все объясняет).
Rec
символ не нужен для определения рекурсивной функции. Если Let
и Var
работают правильно, вы можете определить. Пример, приведенный выше, касается среды для каждой области действия функции, но даже если он будет работать только с глобальной средой, он будет работать.
Для определения типов Let
здесь. Здесь, учитывая взаимную рекурсивную функцию, поэтому используйте модуль graph, но сейчас не обращайте на это внимания. Имя, привязанное к Let
нему, может принимать несколько выражений, хотя так же хорошо, как и одно.
Тогда inferBinds
это было бы просто. Он принимает Name
и Expr
( Maybe Type
для аннотации типа, поэтому может забыть его) и возвращает Type
with [Constraint]
(они входят в комплект as Answer
). Вот как собирать ограничения.
После того, как вы получите ограничения, это так просто. См solve
. раздел Функция. Здесь solve
тип переменных определяется рекурсивно с помощью ограничений. См . Также unify
и bind
.
Мне действительно нужно написать о подстановке, новых переменных и так далее, Но я слишком устал, чтобы объяснять дальше. Если вы хотите узнать подробнее, настоятельно рекомендую ознакомиться с типами и языками программирования.
Комментарии:
1. Я ценю ваше объяснение, но это слишком сложно для меня, кто не знаком с Haskell.
2. Я решил эту проблему, но я не уверен, правильно ли это.
ty en (rec (Lam binds e)) = v where v = ty (binds:en) e
3. Основная идея заключается в сборе ограничений и решении уравнений. Например, если вывести типы
Let "f" (Lam "x" (Var "x")) (App (Var "f") (Int 1))
, мы можем получить ограниченияx = a
,f = x -> x
,1 = Int
,f 1 = b
иexpr = b
. Решите это уравнение, будьте выведеныexpr = Int
. Вышесказанное лишь немного усложняет это.