首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >‘`ap zip尾部’表达式是如何工作的?

‘`ap zip尾部’表达式是如何工作的?
EN

Stack Overflow用户
提问于 2013-10-04 13:03:17
回答 2查看 919关注 0票数 11

我想知道如何免费编写f x = zip x (tail x)。所以我使用了无点程序,结果是f = ap zip tailap是Control.Monad的一个函数

我不明白这个无意义的定义是如何运作的。我希望我能从类型的角度来理解它。

代码语言:javascript
运行
复制
import Control.Monad (ap)
let f = ap zip tail
let g = ap zip
:info ap zip tail f g
ap :: Monad m => m (a -> b) -> m a -> m b
    -- Defined in `Control.Monad'
zip :: [a] -> [b] -> [(a, b)]   -- Defined in `GHC.List'
tail :: [a] -> [a]      -- Defined in `GHC.List'
f :: [b] -> [(b, b)]    -- Defined at <interactive>:3:5
g :: ([a] -> [b]) -> [a] -> [(a, b)]
    -- Defined at <interactive>:4:5

通过查看表达式ap zip tail,我会认为zip是ap的第一个参数,尾巴是ap的第二个参数。

代码语言:javascript
运行
复制
Monad m => m (a -> b) -> m a -> m b
           \--------/   \---/
              zip        tail

但这是不可能的,因为ziptail的类型与ap所需的函数完全不同。即使考虑到名单是一个单一的种类。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-10-04 13:34:06

因此,ap的类型签名是Monad m => m (a -> b) -> m a -> m b。您已经将它作为参数给出了ziptail,所以让我们看看它们的类型签名。

tail :: [a] -> [a] ~ (->) [a] [a]开始(这里~是类型的相等运算符),如果我们将这种类型与ap的第二个参数的类型进行比较,

代码语言:javascript
运行
复制
 (->) [x]  [x] ~ m a
((->) [x]) [x] ~ m a

我们得到了a ~ [x]m ~ ((->) [x]) ~ ((->) a)。我们已经可以看到,我们所处的单一模式是(->) [x],而不是[]。如果我们将可能的内容替换为ap的类型签名,就会得到:

代码语言:javascript
运行
复制
(((->) [x]) ([x] -> b)) -> (((->) [x]) [x]) -> (((->) [x]) b)

因为这不是很好的可读性,所以它通常可以写成

代码语言:javascript
运行
复制
  ([x] -> ([x] -> b)) -> ([x] -> [x]) -> ([x] -> b)
~ ([x] ->  [x] -> b ) -> ([x] -> [x]) -> ([x] -> b)

zip的类型是[x] -> [y] -> [(x, y)]。我们已经可以看到,这与ap的第一个参数是一致的

代码语言:javascript
运行
复制
[x]         ~    [x]   
[y]         ~    [x]   
[(x, y)]    ~    b

在这里,我列出了垂直的类型,这样您就可以很容易地看到哪些类型排列起来。所以很明显,x ~ xy ~ x[(x, y)] ~ [(x, x)] ~ b,所以我们可以完成将b ~ [(x, x)]替换成ap的类型签名并获得

代码语言:javascript
运行
复制
([x] -> [x] -> [(x, x)]) -> ([x] -> [x]) -> ([x] -> [(x, x)])
--   zip                        tail        ( ap  zip  tail )
--                                            ap  zip  tail u = zip u (tail u)

我希望这能帮你弄清楚。

编辑:作为评论中的danvari pointed out,monad (->) a有时被称为读取器monad。

票数 11
EN

Stack Overflow用户

发布于 2015-09-16 02:22:49

要理解这一点有两个方面:

  1. 类型魔法
  2. 实施的信息流

首先,这帮助我理解了类型的魔术

代码语言:javascript
运行
复制
1) zip          : [a] → ( [a] → [(a,a)] )
2) tail         : [a] → [a]
3) zip <*> tail : [a] → [(a,a)]

4) <*> : Applicative f ⇒ f (p → q) → f p → f q

在这种情况下,对于<*>来说,

代码语言:javascript
运行
复制
5) f x = y → x

注意,在5中,f是一个类型构造函数。将f应用于x会产生一种类型。此外,在这里,=被重载为类型的等价性。

y目前是位持有者,在本例中,它是[a],这意味着

代码语言:javascript
运行
复制
6) f x = [a] -> x

使用6,我们可以重写1,2和3如下:

代码语言:javascript
运行
复制
7) zip          : f ([a] → [(a,a)])
8) tail         : f [a]
9) zip <*> tail : f ([a] → [(a,a)])  →  f [a]  →  f [(a,a)]

因此,看看4,我们用以下几个字来代替:

代码语言:javascript
运行
复制
10) p = [a]
11) q = [(a,a)]
12) f x =  [a] → x

(在此再次重复6次为12次)

其次,信息流,即实际的功能。这比较容易,从y →的定义可以看出,这里用不同的标识符名重写了y →,并使用infix样式:

代码语言:javascript
运行
复制
13) g <*> h $ xs = g xs (h xs)

代以:

代码语言:javascript
运行
复制
14) g = zip
15) h = tail

给予:

代码语言:javascript
运行
复制
zip <*> tail $ xs        (Using 14 and 15)
  ==
zip xs (tail xs)         (Using 13 )
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19181917

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档