3

我从Frisby 教授的《函数式编程最充分指南》中走出来,似乎对 Maybe 有一种误解。

我相信:

map(add1, Just [1, 2, 3])
// => Just [2, 3, 4]

我对上述指南的感觉是Maybe.map应该尝试调用Array.map数组,本质上是返回Just(map(add1, [1, 2, 3])

当我尝试使用Sanctuary的 Maybe 类型和最近Elm的 Maybe 类型时,我很失望地发现他们都不支持这个(或者,也许我不明白他们是如何支持这个的)。

在圣域,

> S.map(S.add(1), S.Just([1, 2, 3]))
! Invalid value

add :: FiniteNumber -> FiniteNumber -> FiniteNumber
                       ^^^^^^^^^^^^
                            1

1)  [1, 2, 3] :: Array Number, Array FiniteNumber, Array NonZeroFiniteNumber, Array Integer, Array ValidNumber

The value at position 1 is not a member of ‘FiniteNumber’.

在榆树,

> Maybe.map sqrt (Just [1, 2, 3])
-- TYPE MISMATCH --------------------------------------------- repl-temp-000.elm

The 2nd argument to function `map` is causing a mismatch.

4|   Maybe.map sqrt (Just [1, 2, 3])
                     ^^^^^^^^^^^^^^
Function `map` is expecting the 2nd argument to be:

    Maybe Float

But it is:

    Maybe (List number)

同样,我觉得我应该能够将 aJust(Just(1))视为 a Just(1)。另一方面,我的直觉[[1]]完全相反。显然,map(add1, [[1]])应该返回[NaN]而不是[[2]]或任何其他东西。

在 Elm 中,我能够做到以下几点:

> Maybe.map (List.map (add 1)) (Just [1, 2, 3])
Just [2,3,4] : Maybe.Maybe (List number)

这是我想做的,但不是我想做的。

一张地图应该如何覆盖Maybe List?

4

2 回答 2

7

你有两个函子要处理:MaybeList. 您正在寻找的是某种将它们结合起来的方法。您可以通过函数组合简化您发布的 Elm 示例:

> (Maybe.map << List.map) add1 (Just [1, 2, 3])
Just [2,3,4] : Maybe.Maybe (List number)

这实际上只是您发布的示例的简写,您说这不是想要的方式。

Sanctuary 有一个compose功能,所以上面可以表示为:

> S.compose(S.map, S.map)(S.add(1))(S.Just([1, 2, 3]))
Just([2, 3, 4])

同样,我觉得我应该能够将 aJust(Just(1))视为Just(1)

这可以使用包中的来join完成elm-community/maybe-extra

join (Just (Just 1)) == Just 1
join (Just Nothing)  == Nothing
join Nothing         == Nothing

Sanctuary 也有一个join功能,因此您可以执行以下操作:

S.join(S.Just(S.Just(1))) == Just(1)
S.join(S.Just(S.Nothing)) == Nothing
S.join(S.Nothing)         == Nothing
于 2017-08-03T16:49:23.953 回答
5

正如 Chad 提到的,您想要转换嵌套在两个函子中的值。

让我们从每个单独映射开始以获得舒适:

> S.map(S.toUpper, ['foo', 'bar', 'baz'])
['FOO', 'BAR', 'BAZ']

> S.map(Math.sqrt, S.Just(64))
Just(8)

让我们考虑一下地图的一般类型:

map :: Functor f => (a -> b) -> f a -> f b

现在,让我们将这种类型专门用于上述两种用途:

map :: (String -> String) -> Array String -> Array String

map :: (Number -> Number) -> Maybe Number -> Maybe Number

到目前为止,一切都很好。但是在您的情况下,我们希望映射 type 的值Maybe (Array Number)。我们需要一个这种类型的函数:

:: Maybe (Array Number) -> Maybe (Array Number)

如果我们 map over,S.Just([1, 2, 3])我们需要提供一个函数,该函数将[1, 2, 3]内部值作为参数。所以我们提供给S.map的函数必须是 type 的函数Array (Number) -> Array (Number)S.map(S.add(1))就是这样一个功能。把这一切放在一起,我们得出:

> S.map(S.map(S.add(1)), S.Just([1, 2, 3]))
Just([2, 3, 4])
于 2017-08-03T17:15:20.210 回答