Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 为什么有";映射(过滤器fst)“;“类型”;[Bool,a]->;[(Bool,a)]”;?_Haskell_Types_Functional Programming_Type Inference_Unification - Fatal编程技术网

Haskell 为什么有";映射(过滤器fst)“;“类型”;[Bool,a]->;[(Bool,a)]”;?

Haskell 为什么有";映射(过滤器fst)“;“类型”;[Bool,a]->;[(Bool,a)]”;?,haskell,types,functional-programming,type-inference,unification,Haskell,Types,Functional Programming,Type Inference,Unification,我试图理解为什么这个函数 map (filter fst) 有那种 [[(Bool, a)]] -> [[(Bool, a)]] 如果filter必须接收一个返回Bool类型的函数,而fst只返回元组的第一个元素,“filter-fst”如何工作 filter :: (a -> Bool) -> [a] -> [a] fst :: (a, b) -> a 谁能给我解释一下吗?谢谢;) fst是一个返回布尔值的函数,只要您限制元组的第一个元素为布尔值(第二个元素

我试图理解为什么这个函数

map (filter fst)
有那种

[[(Bool, a)]] -> [[(Bool, a)]]
如果filter必须接收一个返回Bool类型的函数,而fst只返回元组的第一个元素,“filter-fst”如何工作

filter :: (a -> Bool) -> [a] -> [a]
fst :: (a, b) -> a

谁能给我解释一下吗?谢谢;)

fst
是一个返回布尔值的函数,只要您限制元组的第一个元素为布尔值(第二个元素可以是任何元素,因此
(Bool,a)

但是,我们也可以将类型变量交换为
fst
,以获得:

:t fst       -- (c,b) -> c
因此,
filter
的第一个参数的类型是
a->Bool
,而
fst
本身是
(c,b)->c
。现在我们尝试将其组合起来(我认为这称为统一):

由此,我们可以推断
c
必须是
Bool
(因为右手侧必须相等)并获得:

1st arg of filter:  a        -> Bool
fst:                (Bool,b) -> Bool
1st arg of filter:  (Bool,b) -> Bool
fst:                (Bool,b) -> Bool
从上面,我们推断
a
必须是
(Bool,b)
,并获得:

1st arg of filter:  a        -> Bool
fst:                (Bool,b) -> Bool
1st arg of filter:  (Bool,b) -> Bool
fst:                (Bool,b) -> Bool
我们完成了

如果filter必须接收一个返回Bool类型的函数,而fst只返回元组的第一个元素,“filter-fst”如何工作

从某种意义上说,你已经回答了自己的问题!让我们把它分解一下:

筛选器必须接收返回布尔类型的函数

好的,让我们看看你传递的是什么:
fst
fst
是一个函数吗?是的,它是,所以我们已经记下了第一部分。它是否返回一个
Bool
?好吧,让我们看看它的功能:

fst只返回元组的第一个元素

因此,如果元组的第一个元素是
Bool
,那么是的,它确实返回Bool!但是,如果元组的第一个元素不是
Bool
,它不会并且将无法通过类型检查

让我们再看一看您设置的类型。我将更改类型变量的名称,以使事情更清楚:

filter :: (a -> Bool) -> [a] -> [a]
fst :: (b, c) -> b
fst
接受一个
(b,c)
并返回一个
b
,而filter期望一个函数接受
a
并返回一个
Bool
。我们正在传入
fst
,因此上面的
a
必须是
(b,c)
因为这是
fst
的第一个参数。我们传递到
filter
的函数的返回值必须是a
Bool
,因此上面的
b
必须是a
Bool
。而
c
可以是任何东西,因为它根本不被filter使用。用这些值替换
a
b
为我们提供了过滤器fst的最终类型:

filter fst :: [(Bool, c)] -> [(Bool, c)]
最后,
map
的类型是:

map :: (d -> e) -> [d] -> [e]
(同样,我在这里重命名了类型变量,只是为了将它们与上面使用的变量区分开来,但请记住,它们的名称并不重要,只要它们在类型注释的范围内是一致的)

map(filter fst)
将我们上面定义的
filter fst
作为第一个参数传递给
map
。将参数替换为
d
,并将结果替换为
e
,我们可以看到此函数必须是
[(Bool,c)]->[(Bool,c)]
,换句话说,
d
e
都是
(Bool,c)
。将它们插入函数,我们得到最终类型:

map (filter fst) :: [[(Bool, c)]] -> [[(Bool, c)]]

因为在danielpwright的答案发布之前我已经写下了这篇文章,所以我还是发布了它。我只是在这里回顾一下我对
过滤器fst
类型的思考过程

首先,写下类型签名(更改fst,使其类型变量名不会与筛选器的类型变量名冲突):

(a->Bool)
((b,c)->b)
匹配:

b
必须是
Bool
,这意味着
a
必须是
(Bool,c)

通过使用此信息专门化
过滤器
,它将成为:

filter :: ((Bool,c) -> Bool) -> [(Bool,c)] -> [(Bool,c)]
这导致了

filter fst :: [(Bool, c)] -> [(Bool, c)]

你真的只需要解一些类型方程。让我们开始:

 filter :: (a -> Bool) -> [a] -> [a]
 fst    :: (b, c) -> b
因此,
filter fst::[a]->[a]
其中
a
是以下类型方程的解:

 a -> Bool = (b, c) -> b
a -> b = [(Bool, c)] -> [(Bool, c)]
这意味着

 a    = (b, c)
 Bool = b
 a = (Bool, c)
a = [(Bool, c)]
b = [(Bool, c)]
这意味着

 a    = (b, c)
 Bool = b
 a = (Bool, c)
a = [(Bool, c)]
b = [(Bool, c)]
因此,
过滤器fst::[(Bool,c)]->[(Bool,c)]

现在我们有:

map        :: (a -> b) -> [a] -> [b]
filter fst :: [(Bool, c)] -> [(Bool, c)]
因此,
map(filter fst)::[a]->[b]
其中
a
b
由以下类型方程给出:

 a -> Bool = (b, c) -> b
a -> b = [(Bool, c)] -> [(Bool, c)]
这意味着

 a    = (b, c)
 Bool = b
 a = (Bool, c)
a = [(Bool, c)]
b = [(Bool, c)]

因此,
map(filter fst)::[[(Bool,c)]->[[(Bool,c)]]

正如其他人所做的那样,我想在这里解类型方程;但我想以更直观的方式写下它们,这样可以以更自动的方式进行推导。让我们看看

filter :: (  a   -> Bool) -> [a] -> [a]
fst    ::  (c,d) -> c              -- always use unique type var names, 
------------------------           --   rename freely but consistently
filter fst :: [a] -> [a],    a -> Bool  ~  (c,d) -> c
                             a ~ (c,d)  ,  Bool ~ c
                             a ~ (Bool,d)
           ---------------------------
           :: [(Bool,d)] -> [(Bool,d)]
纯机械的东西。:)用这个

map        :: (     a     ->     b     ) -> [a] -> [b]
filter fst ::  [(Bool,d)] -> [(Bool,d)]
------------------------------
map (filter fst) :: [a] -> [b],     a ~ [(Bool,d)]  ,  b ~ [(Bool,d)]
                 -------------------------------
                 :: [[(Bool,d)]] -> [[(Bool,d)]]
最后一个类型中的类型变量可以自由重命名以便于可读(当然是以一致的方式)

我的答案对其他答案中已经显示的内容的唯一补充是这个建议(我认为这很重要):如果你遵循这个简单的原则,将一件事写在另一件事的下面,以非常机械、自动的方式执行这些类型的统一将变得非常容易(从而减少出错的可能性)


关于这方面的另一个例子,包括一个实际的类型派生Prolog程序,请参见。

我认为您要查找的术语是“限制”(即限制类型变量的类型)。术语“统一”用于逻辑编程。它是一种执行策略,通过统一逻辑谓词中的变量使逻辑谓词为真。简单地说,“统一”是一个反复试验的过程。它用于确定值的有效性。与“限制”相反这不是一个反复试验的过程。它就像一次完成任务的过程。虽然这两个概念相似,但它们肯定不一样。@AaditMShah:不,这是unifica