【问题标题】:How should I map over Maybe List?我应该如何映射可能列表?
【发布时间】:2018-01-11 09:24:39
【问题描述】:

我离开 Professor Frisby's Mostly Adequate Guide to Functional Programming 时似乎对 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)

同样,我觉得我应该能够将Just(Just(1)) 视为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?

【问题讨论】:

  • 在 Haskell 中,有一个为 composition of two Functors 定义的 Functor 实例,因此 fmap 在组合的 Functor 内部可以工作两层。在import Data.Functor.Compose 之后,getCompose $ fmap (1+) $ Compose $ Just [1,2,3] 返回Just [2,3,4]Compose/getCompose 只是类型系统的助手。
  • Haskell 拥有一切,嗯!?

标签: functional-programming monads elm maybe sanctuary


【解决方案1】:

您有两个函子要处理: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])

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

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

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

【讨论】:

    【解决方案2】:

    正如 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
    

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

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

    如果我们映射S.Just([1, 2, 3]),我们需要提供一个函数,它以[1, 2, 3](内部值)作为参数。所以我们提供给S.map的函数必须是Array (Number) -&gt; Array (Number)类型的函数。 S.map(S.add(1)) 就是这样一个功能。综上所述,我们得出:

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

    【讨论】:

    • 嘿!你就是那个家伙! :) 上帝保佑 stackoverflow。
    • 几个月后,我明白了!函数add1number -&gt; number,map 将add1 提升为Maybe number -&gt; Maybe number。我试图将一个接受和参数Maybe number 的函数应用于List number 类型的值。那是行不通的!在上一个示例中,您首先将add1 提升为F number -&gt; F number,然后将其提升为Maybe F number -&gt; Maybe F number,最后将其应用于Maybe F number 类型的值。
    • 我可以使用S.map(S.add(1)) 创建一个函数F number -&gt; F number,然后将该函数应用于S.Just(1)[1, 2, 3],即使它们具有不同的类型,这真的很酷!一种是Maybe numberList number。多态的魔力!
    猜你喜欢
    • 2021-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多