这是 Haskell 实现中的一个错误吗?

问题描述 投票:0回答:1

在研究

MaybeT
的 Haskell 实现时,我偶然发现了一个有趣的问题。某些函数执行产生的结果与我的预期不同。

我不确定这是一个错误还是完全是别的什么。

问题描述如下:

liftM
(definition)是
fmap
类型下的
Monad
函数。 它的类型签名是:

liftM :: (a -> b) -> m a -> m b

Just
是 Maybe 类型的构造函数。

Just 1
结果为
Just(1)

Just Nothing
结果为
Just(Nothing)

但是,当我使用

liftM Just
(相当于
liftM $ Just
)时,它们的类型签名是相同的:

liftM Just :: Monad m => m a1 -> m (Maybe a1)

现在,当我执行以下代码行时:

(liftM Just) $ Just(1)

结果是:

Just(Just 1) :: Maybe (Maybe t)  -- this aligns with my expectations.

但是当我执行这行代码时:

(liftM Just) $ Nothing   -- I expected: Just(Nothing) :: Maybe(Maybe a), 
                         -- but actual result: Nothing :: Maybe a ??  
 
(liftM Just) $ (Left 1)  -- I expected: Left(Just 1), but actual result: Left 1 ??

问题是 返回的类型与函数的类型签名不匹配。 (

liftM Just
)

我期望的结果是:

Just(Nothing) :: Maybe (Maybe t)
。然而,在
GHCi
中,实际结果是
Nothing :: Maybe t
——这就是我得到的。

这两种类型是不同的。

Just(Nothing) :: Maybe (Maybe a)
Nothing :: Maybe a

Left(Just 1) :: Either (Maybe a) (Maybe a)
Left 1 :: Either 

我觉得

Just(Nothing)
Nothing
代表不同的价值观,对吧?

它们不应该被混为一谈,不是吗?

那么,

liftM Just $ Nothing
返回
Just(Nothing) :: Maybe (Maybe t)
不是更合适吗?

如果我想获得

Just(Nothing)
结果,我该怎么办?

这是 Haskell 的一个错误,还是这种差异背后还有其他原因?

感谢您的帮助!

haskell functional-programming monads
1个回答
0
投票

首先:这与

liftM
没有任何关系。对于任何行为良好的 monad(包括
Maybe
),这确实相当于
fmap
,你应该始终使用它。

让我们引入一个与

Maybe
等效但名称不同的类型,这将使发生的事情更清楚。

data Maybe' a = Nothing' | Just' a
 deriving (Show, Functor)     -- requires {-# LANGUAGE DeriveFunctor #-} on top of your source file

现在,你先写的相当于

> fmap Just $ Just' 1
Just' (Just 1) :: Maybe' (Maybe Integer)

首先要强调的是,

Maybe
Maybe'
单子之间没有相互作用。 (事实上,我们甚至还没有将
Maybe'
创建为 monad!)您只是将某个函数映射到
Maybe'
函子上,而该函数恰好具有类型
Integer -> Maybe Integer

在同一个框架下,你的第二次尝试是

> fmap Just Nothing'
Nothing' :: Maybe' (Maybe Integer)

在这种情况下,您是否通过

Just
并不重要,因为在
Nothing'
上映射任何内容总是会返回
Nothing'
。这与可能不那么令人困惑的情况相同

> fmap (+1) Nothing'
Nothing' :: Maybe' (Maybe Integer)

对于

Either
示例,它基本上是相同的故事,除了
Left
构造函数包含
Nothing'
没有的附加值,但这不参与任何
Functor
语义。

© www.soinside.com 2019 - 2024. All rights reserved.