如何解决理解(,)<$>长度<*>头部的类型
我有这对功能
(,) <$> length :: Foldable t => t a -> b -> (Int,b)
和,
head :: [a] -> a
我想了解的类型
(,) <$> length <*> head
在 (<*>) :: Applicative f => f (a -> b) -> f a -> f b
类型签名中,
f :: (->) [a]
a :: b
b :: (Int -> b)
所以,实例化的类型是:
(->) [a] (Int,b)
然而,我发现它的类型确实是:
(->) [a] (Int,a)
两个问题,如果可以的话:
- 为什么将
b
切换为a
? - 这种类型签名计算的分步过程是什么?
解决方法
让我们继续使用签名
(,) <$> length :: Foldable t => t a -> b -> (Int,b)
但是改变
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
到
(<*>) :: Applicative f => f (x -> y) -> f x -> f y
所以它不会变得混乱。如您所见,显然 f ~ (->) [a]
(假设我们正在使用 foldable 的列表实例),因此 x -> y ~ b -> (Int,b)
,因此 x ~ b
和 y ~ (Int,b)
。这是您错过的部分,可能是因为命名混乱:第二个参数是 f x
或 [a] -> b
,您传入 head
,即 [a] -> a
。这强制 b
与 a
相同,否则类型将无法工作。结果是 f y
或 [a] -> (Int,b)
,除了 b
现在是 a
,为您提供 [a] -> (Int,a)
签名。
派生 (,) <$> length <*> head
类型的一种方法是对 length
和 head
进行抽象,然后考虑生成的 lambda 表达式
\l -> \h -> (,) <$> l <*> h
类型
Applicative f => f a -> f b -> f (a,b)
我们需要的类型分别为 [x] -> Int
和 [x] -> x
的 length
和 head
f a ~ [x] -> Int
f b ~ [x] -> x
因此
f ~ (->) [x] -- hom-functor aka Reader
a ~ Int
b ~ x
产生的结果
([x] -> Int) -> ([x] -> x) -> ([x] -> (Int,x))
作为上述 lambda 表达式的类型。
,另一种导出 (,) <$> length <*> head
类型的方法是通过在每一步中应用定义来逐步计算它:
(,) :: a -> b -> (a,b)
(,) <$> :: f a -> f (b -> (a,b))
(,) <$> length :: [a] -> (b -> (Int,b))
(,) <$> length <*> :: ([a] -> b) -> ([a] -> (Int,) <$> length <*> head :: [a] -> (Int,a)
最棘手的部分是在第三步和第四步中为 (->)[a]
正确应用 f
。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。