| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
 | 
module Substitution where
import Data.FiniteMap
import FlatCurry.Annotated.Types
import FlatCurryGoodies          (TypeAnn)
type Subst = FM
emptySubst :: Ord a => Subst a b
emptySubst = emptyFM (<)
singleSubst :: Ord a => a -> b -> Subst a b
singleSubst = unitFM (<)
mkSubst :: Ord a => [a] -> [b] -> Subst a b
mkSubst vs es = listToFM (<) (zip vs es)
bind :: Ord a => a -> b -> Subst a b -> Subst a b
bind k v s = addToFM s k v
dom :: Subst a b -> [a]
dom = keysFM
range :: Subst a b -> [b]
range = eltsFM
restrict :: Eq a => [a] -> Subst a b -> Subst a b
restrict vs s = filterFM (\v _ -> v `elem` vs) s
findSubstWithDefault :: Ord a => b -> a -> Subst a b -> b
findSubstWithDefault e v s = lookupWithDefaultFM s e v
compose :: SubstBy b => Subst VarIndex b -> Subst VarIndex b -> Subst VarIndex b
compose s1 s2 = mapFM    (\_ e -> subst s1 e)          s2 `plusFM`
                filterFM (\v _ -> not (v `elemFM` s2)) s1
class SubstBy a where
  subst :: Subst VarIndex a -> a -> a
instance SubstBy (AExpr a) where
  subst s v@(AVar       _ i) = findSubstWithDefault v i s
  subst _ l@(ALit       _ _) = l
  subst s (AComb ty ct c es) = AComb ty ct c (map (subst s) es)
  subst s (ALet     ty bs e) = ALet ty (map substBind bs) (subst s e)
    where substBind (v, ve) = (v, subst s ve)
  subst s (AFree    ty vs e) = AFree ty vs (subst s e)
  subst s (AOr     ty e1 e2) = AOr ty (subst s e1) (subst s e2)
  subst s (ACase ty ct e bs) = ACase ty ct (subst s e) (map substBranch bs)
    where substBranch (ABranch p be) = ABranch p (subst s be)
  subst s (ATyped  ty e ty') = ATyped ty (subst s e) ty'
instance SubstBy TypeExpr where
  subst s v@(TVar         i) = findSubstWithDefault v i s
  subst s (FuncType ty1 ty2) = FuncType (subst s ty1) (subst s ty2)
  subst s (TCons      c tys) = TCons c (map (subst s) tys)
  subst _ (ForallType   _ _) = error "Substitution.substTy: ForallType"
type AExpSubst = Subst VarIndex (AExpr TypeAnn)
type TypeSubst = Subst TVarIndex TypeExpr
unify :: [(TypeExpr, TypeExpr)] -> TypeSubst
unify eqs = case unify' emptySubst eqs of
  Nothing  -> error $ "Given type equations are not unifiable: " ++ show eqs
  Just mgu -> mgu
unify' :: TypeSubst -> [(TypeExpr, TypeExpr)] -> Maybe TypeSubst
unify' sub []                = Just sub
unify' sub (eq@(t1, t2):eqs) = case eq of
  (TVar i, TVar j) | i == j          -> unify' sub eqs
                   | otherwise       -> replace i t2
  (TVar i,      _) | i `occursIn` t2 -> Nothing
                   | otherwise       -> replace i t2
  (_     , TVar j) | j `occursIn` t1 -> Nothing
                   | otherwise       -> replace j t1
  (FuncType u1 u2, FuncType v1 v2)   -> unify' sub ([(u1, v1), (u2, v2)] ++ eqs)
  (TCons c1 ts1, TCons c2 ts2)
    | c1 == c2 &&
      length ts1 == length ts2       -> unify' sub (zip ts1 ts2 ++ eqs)
    | otherwise                      -> Nothing
  (ForallType _ _, _)                -> error "Substitution.unify: ForallType"
  (_, ForallType _ _)                -> error "Substitution.unify: ForallType"
  _                                  -> Nothing
 where
  replace k v = unify' (bind k v sub)
    (map (\(s, t) -> ( subst (singleSubst k v) s
                     , subst (singleSubst k v) t)) eqs)
  occursIn tv ty = case ty of
    TVar           i -> tv == i
    FuncType ty1 ty2 -> tv `occursIn` ty1 || tv `occursIn` ty2
    TCons      _ tys -> any (tv `occursIn`) tys
    ForallType   _ _ -> error "Substitution.occursIn: ForallType"
 |