给出一个函数:(a - > a)我们应该使用该函数并将其类型转换为(也许a - >可能是a)。我有点坐在这里尝试一切可能,但我只得到类型可能(a - > a),但我不知道改变实际的输入和输出。所以有人可以给我一些解决这个问题的提示或想法,所以我可以自己尝试一下吗?感谢。
答案 0 :(得分:5)
假设你有
f :: a -> a
你需要构建
g :: Maybe a -> Maybe a
g = ...
我们如何构建它?首先,它是一个参数的函数,所以它应该是这样的:
g = \x -> ...
其次,我们有Maybe
类型的参数,因此我们可以分别分析两个案例:
g = \x -> case x of
Nothing -> ... (1)
Just y -> ... (2)
在(1)中,我们做不了多少:我们无法生成抽象类型a
的值,因此无法使用Just
。我们唯一可以使用的是Nothing
。
在(2)中,我们有三个选择:
a)再次Nothing
,所以我们得到一个无聊的解决方案:
g = \x -> case x of
Nothing -> Nothing
Just y -> Nothing
只是
g = \x -> Nothing
b)或者,我们有y::a
,因此我们可以返回Just y
:
g = \x -> case x of
Nothing -> Nothing
Just y -> Just y
只是
g = \x -> x -- = id
c)或者,我们可以将f
应用于y
,以获得a
类型的新值。我们需要做的就是将这个值包装在Just
:
g = \x -> case x of
Nothing -> Nothing
Just y -> Just (f y)
正如@chi指出的那样,我们可以继续将f
应用于结果,因此我们也可以针对任意数量的Just (f (f ... (f y)...))
返回f
。
只有(c)使用f
,所以这是唯一的非平凡解决方案。
为了完整起见,值得注意的是,对于真实世界的应用,(b)和(c)都是等价的,因为f
除了id
之外什么都不是f
。
正如@amalloy指出的那样,如果我们将id
作为参数而不是全局函数,则不是这种情况,因为只有a->a
可以作为a
用于任何a->a
但是,对于给定的a
,有许多类型为g
的函数。所以,如果你的g :: (a->a)->(Maybe a->Maybe a)
应该是
Maybe
然后(b)和(c)不再相同。
当然,这可以通过多种方式编写:上面的幼稚版本,使用事件Monad
是fmap
,使用来自Functor Maybe
的{{1}}(信用到@amalloy),但结果将是相同的。
答案 1 :(得分:1)
要避免最终的答案真的很难,因为这是一个微不足道的问题,真的。
检查标准函数fmap
的签名(我将删除约束部分,因为我们现在不需要它):
fmap :: (a -> b) -> f a -> f b
您可以将其视为两个参数(a -> b)
和f a
的函数,生成结果f b
。但是,以下签名完全相同:
fmap :: (a -> b) -> (f a -> f b)
钟声响起吗?是的,fmap
也可以看作是一个参数(a -> b)
的函数,从而产生(f a -> f b)
函数。
现在,这些签名中的f
代表具有Functor
实例的任何类型,其中Maybe
就是这种情况。现在,弄清楚其余部分:)