![](/img/trans.png)
[英]How is `[e | x <- xs; y <- ys; ...] = concat[[e | y <- ys; ...] | x <- xs]`
[英]Type of fun g x = ys where ys = [x] ++ filter (curry g x) ys?
我试图理解为什么fun gx = ys where ys = [x] ++ filter (curry gx) ys
的类型fun gx = ys where ys = [x] ++ filter (curry gx) ys
是((a, a) -> Bool) -> a -> [a]
。
我明白那个:
filter :: (a -> Bool) -> [a] -> [a]
和curry :: ((a, b) -> c) -> a -> b -> c
但我不明白如何继续。
下面的方法不一定是最简单或最快的,但它是相对系统的。
严格来说,你正在寻找的类型
\g -> (\ x -> let ys = (++) [x] (filter (curry g x) ys) in ys)
(考虑到类型, let
where
等同,但有时候使用let
更容易推理)
filter :: (a -> Bool) -> [a] -> [a]
curry :: ((a, b) -> c) -> a -> b -> c
不要忘记你也在使用
(++) :: [a] -> [a] -> [a]
让我们首先看一下语法树的“最深”部分:
curry g x
我们有g
和x
,我们之前还没有见过,所以我们假设他们有一些类型:
g :: t1
x :: t2
我们也有curry
。 在出现这些函数的每个点上,类型变量( a
, b
, c
)可以有不同的特性,因此每次使用这些函数时,最好用新名称替换它们。 此时, curry
有以下类型:
curry :: ((a1, b1) -> c1) -> a1 -> b1 -> c1
如果可以统一以下类型,我们只能说curry gx
:
t1 ~ ((a1, b1) -> c1) -- because we apply curry to g
t2 ~ a1 -- because we apply (curry g) to x
那么假设这也是安全的
g :: ((a1, b1) -> c1)
x :: a1
---
curry g x :: b1 -> c1
让我们继续:
filter (curry g x) ys
我们第一次看到ys
,所以现在让它保持在ys :: t3
。 我们还必须实例化filter
。 所以在这一点上,我们知道
filter :: (a2 -> Bool) -> [a2] -> [a2]
ys :: t3
现在我们必须匹配filter
参数的类型:
b1 -> c1 ~ a2 -> Bool
t3 ~ [a2]
第一个约束可以细分为
b1 ~ a2
c1 ~ Bool
我们现在知道以下内容:
g :: ((a1, a2) -> Bool)
x :: a1
ys :: [a2]
---
filter (curry g x) ys :: [a2]
我们继续吧。
(++) [x] (filter (curry g x) ys)
我不会花太多时间来解释[x] :: [a1]
,让我们看看(++)
的类型:
(++) :: [a3] -> [a3] -> [a3]
我们得到以下约束:
[a1] ~ [a3] -- [x]
[a2] ~ [a3] -- filter (curry g x) ys
由于这些约束可以减少到
a1 ~ a3
a2 ~ a2
我们只是将所有这些a
a1
:
g :: ((a1, a1) -> Bool)
x :: a1
ys :: [a1]
---
(++) [x] (filter (curry g x) ys) :: [a1]
现在,我将忽略ys
'类型被推广,并专注于
\x -> let { {- ... -} } in ys
我们知道我们需要什么类型的x
,和我们知道的类型ys
,所以我们现在知道
g :: ((a1, a1) -> Bool)
ys :: [a1]
---
(\x -> let { {- ... -} } in ys) :: a1 -> [a1]
以类似的方式,我们可以得出结论
(\g -> (\x -> let { {- ... -} } in ys)) :: ((a1, a1) -> Bool) -> a1 -> [a1]
此时,你只需要重命名(实际上,概括,因为你想将它绑定到fun
)类型变量,你就有了答案。
我们可以使用一般方案,或多或少地以机械方式推导Haskell中的类型
foo x = y -- is the same as
foo = \x -> y -- so the types are
foo :: a -> b , x :: a , y :: b -- so that
foo x :: b
这意味着,例如
f x y z :: d , x :: a , y :: b, z :: c
限嗣继承
f x y :: c -> d
f x :: b -> c -> d
f :: a -> b -> c -> d
使用这些简单的技巧,类型推导对你来说将变得微不足道。 在这里,与
filter :: (a -> Bool) -> [a] -> [a]
curry :: ((a, b) -> c) -> a -> b -> c
(++) :: [a] -> [a] -> [a]
我们简单地写下仔细排列的东西,以自上而下的方式处理它,一致地重命名并替换类型变量,并记录侧面的类型等价:
fun g x = ys where ys = [x] ++ filter (curry g x) ys
fun g x :: c , ys :: c
fun g :: b -> c , x :: b
fun :: a -> b -> c , g :: a
ys = [x] ++ filter (curry g x) ys c ~ c (++) [x] (filter (curry g x) ys) :: c (++) :: [a1] -> [a1] -> [a1] ----------------------------------------------- (++) :: [b] -> [b] -> [b] , a1 ~ b , c ~ [b] filter (curry g x ) ys :: [b] filter :: (a2 -> Bool) -> [a2] -> [a2] , a2 ~ b -------------------------------------- filter :: (b -> Bool) -> [b] -> [b] curry g x :: b -> Bool curry :: ((a3, b) -> c3 ) -> a3 -> b -> c3 , c3 ~ Bool , a3 ~ b ------------------------------------------- curry :: ((b , b) -> Bool) -> b -> b -> Bool , a ~ ((b,b) -> Bool)
所以我们有a ~ ((b,b) -> Bool)
和c ~ [b]
,因此
fun :: a -> b -> c
fun :: ((b,b) -> Bool) -> b -> [b]
这与((a,a) -> Bool) -> a -> [a]
,直到类型变量的一致重命名。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.