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 “理解”;单子m";在>&燃气轮机=_Haskell - Fatal编程技术网

Haskell “理解”;单子m";在>&燃气轮机=

Haskell “理解”;单子m";在>&燃气轮机=,haskell,Haskell,查看Haskell的绑定: Prelude> :t (>>=) (>>=) :: Monad m => m a -> (a -> m b) -> m b 我被下面的例子弄糊涂了: Prelude> let same x = x Prelude> [[1]] >>= \x -> same x [1] 查看>=的签名,\x->same x如何使用a->mb进行类型检查 我本以为\x->same x会产生一个[b

查看Haskell的绑定:

Prelude> :t (>>=)
(>>=) :: Monad m => m a -> (a -> m b) -> m b
我被下面的例子弄糊涂了:

Prelude> let same x = x

Prelude> [[1]] >>= \x -> same x
[1]
查看
>=
的签名,
\x->same x
如何使用
a->mb
进行类型检查

我本以为
\x->same x
会产生一个
[b]
类型,因为我理解这里的
单子m
类型是
[]

我本以为
\x->same x
会产生
[b]
类型,因为据我所知,这里的
单子m
类型是
[]

它之所以如此,是因为它确实如此

我们有

[[1]] >>= \ x -> same x
=
[[1]]       >>=    \ x -> x
[[Int]]          [Int] -> [Int]        :: [Int]
[] [Int]         [Int] -> [] Int       :: [] Int
m  a             a        m  b            m  b

有时,
[]
描述了一种“不确定性”效应。其他时候,
[]
正在描述类似容器的数据结构。事实上,很难区分这两个目的中的哪一个得到了满足,这是一些人非常自豪的一个特点。我不准备同意他们的观点,但我知道他们在做什么。

这里的单子是
[a]
,这个例子毫无意义地复杂。这会更清楚:

Prelude> [[1]] >>= id
[1]
正如

Prelude> [[1]] >>= const [2]
[2]

i、 e.
>=
concatMap
,与
id

一起使用时是
concat
,正如您所说
m
[]
。然后
a
[Integer]
(为了简单起见,忽略数字是多态的这一事实),而
b
整数。因此
a->mb
首先变成
[Integer]->[Integer]
我们应该使用标准版本的
相同的
,它被称为
id

现在,让我们重命名一些类型变量

id :: (a'' ~ a) => a -> a''
这意味着:
id
的签名是两种类型之间的函数映射的签名,额外的约束是两种类型相等。仅此而已–我们不需要任何特殊属性,如“平坦”

我为什么要这样写?如果我们也重命名绑定签名中的一些变量

(>>=) :: (Monad m, a'~m a, a''~m b) => a' -> (a -> a'') -> a''
…很明显,我们可以插入
id
,因为类型变量已经被相应地命名了。来自
id
的类型相等约束
a'>a
被简单地带到化合物的签名,即

(>>=id) :: (Monad m, a'~m a, a''~m b, a''~a) => a' -> a''
或者,简化一下

(>>=id) :: (Monad m, a'~m a, m b~a) => a' -> m b
(>>=id) :: (Monad m, a'~m (m b))    => a' -> m b
(>>=id) :: (Monad m)                => m (m b) -> m b
这样做的目的是,将嵌套的monad展平到同一个monad的单个应用程序中。非常简单,事实上这是一个“更基本”的运算:数学家们有两个态射
η::a->ma
(我们知道,它是
返回
)和
μ::m(ma)->ma
——是的,这就是你刚刚发现的。在哈斯克尔,它被称为

查看
>=
的签名,
\x->same x
如何使用
a->mb
进行类型检查

其实很简单。查看类型签名:

same       :: x -> x

(>>=)      :: Monad m => m a -> (a -> m b) -> m b

(>>= same) :: Monad m => m a -> (a -> m b) -> m b
                                |________|
                                    |
                                 x -> x
因此:

x := a

-- and

x := m b

-- and by transitivity

a := x := m b

-- or

a := m b
因此:

(>>= same) :: Monad m => m (m b) -> m b
这只是来自
Control.Monad
模块的
join
函数,对于list Monad,它与
concat
函数相同。因此:

[[1]] >>= \x -> same x

-- is the same as the following via eta reduction

[[1]] >>= same

-- is the same as

(>>= same) [[1]]

-- is the same as

join [[1]]

-- is the same as

concat [[1]]

-- evaluates to

[1]
我本以为
\x->same x
会产生
[b]
类型,因为据我所知,这里的
单子m
类型是
[]

确实如此。具有类型
x->x
\x->same x
函数专用于类型
[b]->[b]
,如上所述。因此,
(>>=same)
的类型为
[[b]]->[b]
,与
concat
函数相同。它将列表展平

concat
函数是
join
函数的一个特化,它将嵌套的单子展平


应该注意的是,monad可以用
>=
fmap
join
来定义。致:

尽管Haskell根据
return
>=
函数定义了单子,但也可以根据
return
和其他两个操作
join
fmap
定义单子。这个公式更符合范畴论中单子的原始定义。
fmap
操作的类型为
Monad m=>(a->b)->ma->mb
,它在两种类型之间取一个函数,并生成一个对Monad中的值执行“相同操作”的函数。使用类型为
Monad m=>m(ma)->ma
join
操作将两层一元信息“展平”为一层

这两种配方的关系如下:

fmap f m = m >>= (return . f)
join n   = n >>= id

m >>= g  ≡ join (fmap g m)
这里,
m
具有类型
Monad m=>ma
n
具有类型
Monad m=>m(ma)
f
具有类型
a->b
g
具有类型
Monad m=>a->mb,其中
a
b
是底层类型

fmap
函数是为类型和函数类别中的任何函子定义的,而不仅仅是为单子定义的。它应满足函子定律:

fmap id      ≡ id
fmap (f . g) ≡ (fmap f) . (fmap g)
return
函数通过考虑将值“提升”到函子中的能力来刻画同一类别中的指向函子。它应符合以下法律:

return . f ≡ fmap f . return
此外,
join
函数是单子的特征:

join . fmap join     ≡ join . join
join . fmap return   ≡ join . return = id
join . fmap (fmap f) ≡ fmap f . join

希望这能有所帮助。

正如一些人评论的那样,你在这里发现了一个关于单子的非常可爱的特性。为了便于参考,让我们看看bind的签名:

:: Monad m => m a -> (a -> m b) -> m b
在您的例子中,类型
a===mb
,就像您有a
[[a]]
m(ma)
一样。因此,如果您重写上述绑定操作的签名,您将得到:

:: Monad m => m (m b) -> ((m b) -> m b) -> m b
我提到这很可爱,因为从广义上讲,这适用于任何嵌套的monad。e、 g

:: [[b]] -> ([b] -> [b]) -> [b]
:: Maybe (Maybe b) -> (Maybe b -> Maybe b) -> Maybe b
:: Reader (Reader b) -> (Reader b -> Reader b) -> Reader b
如果您查看此处应用的get函数,您将看到它是标识函数(例如,
id
<