0

我想手动导出类型:

f1 x xs = (filter . (<)) x xs

我们第一次看到x,所以:

x :: t1

然后(<)有这种类型:

(<) :: Ord a1 => a1 -> a1 -> Bool

我们只能说(< x)是否可以统一以下类型:

t1  ~  a1

然后

x :: a1

所以

(<x) :: Ord a1 => a1 -> Bool

过滤器有这种类型

filter :: (a2 -> Bool) -> [a2] -> [a2]

第一次看到xs,所以:

xs :: t2

我们只能说(filter . (<)) x xs是否可以统一以下类型:

a1 -> Bool ~ a2 -> Bool
t2  ~ [a2]

因此,当正确的类型是(询问 GHCi)时,我得到了f1 :: (a2 -> Bool) -> [a2] -> [a2]与 相同的类型。filterOrd a => a -> [a] -> [a]

有什么帮助吗?

4

2 回答 2

6

约束

a1 -> Bool ~ a2 -> Bool

可以分解为

a1 ~ a2

显然是真的

Bool ~ Bool

所以你有a1 ~ a2. 您已经知道xis a1xsis [a2],并且由于filter,结果类型是[a2]。因此,您最终得到:

f1 :: Ord a2 => a2 -> [a2] -> [a2]

(不要忘记a1从 . 得到的类约束(<)。)

于 2014-04-27T18:52:22.337 回答
3

我们可以以自上而下的方式处理给定的表达式。这样就不需要猜测去哪里了,推导纯粹是机械地发生的,错误的空间最小:

f1    x   xs = (filter . (<)) x xs
f1    x   xs :: c                        (filter . (<)) x xs :: c
f1    x :: b -> c                        xs :: b
f1 :: a -> b -> c                        x  :: a 

(filter .  (<)) x      xs  :: c
filter    ((<)  x)  ::  b  -> c          c ~ [d] , b ~ [d]
filter :: (d->Bool) -> [d] -> [d]        (<) x :: d -> Bool

(<) :: (Ord a) => a -> a -> Bool
(<)               x :: d -> Bool         a ~ d , (Ord a)

f1  :: (Ord a) => a -> [a] -> [a]

解决这个问题的另一种方法是注意可以在 的定义中执行eta 减少f1

f1    x   xs = (filter . (<)) x xs
f1           = (.) filter (<)

(.) :: (   b      ->     c     ) -> (           a ->   b      ) -> (a->c)
(.)             filter                           (<)            ::   t1
(.) :: ((d->Bool) -> ([d]->[d])) -> ((Ord a) => a -> (a->Bool)) ->   t1

        b ~ d -> Bool , c ~ [d] -> [d] , t1 ~ a -> c , (Ord a)
        b ~ a -> Bool
        -------------
            d ~ a

f1 :: t1 ~ (Ord a) => a -> c 
         ~ (Ord a) => a -> [d] -> [d]
         ~ (Ord a) => a -> [a] -> [a]

当然,我们在类型中使用箭头的右关联性:a -> b -> c实际上是a -> (b -> c)

我们还使用类型推导的通用方案

f    x    y    z :: d
f    x    y :: c -> d      , z :: c
f    x :: b -> c -> d      , y :: b
f :: a -> b -> c -> d      , x :: a
于 2014-04-27T21:29:02.300 回答