繁体   English   中英

有趣的类型gx = ys,其中ys = [x] ++ filter(curry gx)ys?

[英]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

我们有gx ,我们之前还没有见过,所以我们假设他们有一些类型:

g :: t1
x :: t2

我们也有curry 在出现这些函数的每个点上,类型变量( abc )可以有不同的特性,因此每次使用这些函数时,最好用新名称替换它们。 此时, 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM