在 Purescript 中从元组中提取一个 Maybe

Pulling a Maybe out of a Tuple in Purescript

我有一个看起来像这样的函数:

import Data.Bifunctor (lmap)
import Data.Int (fromString)

keyToInt :: forall a. Tuple String a -> Tuple (Maybe Int) a
keyToInt = lmap fromString 

我想要的是这样的类型签名:

keyToInt :: forall a. Tuple String a -> Maybe (Tuple Int a)

这似乎有效:

keyToInt :: forall a. Tuple String a -> Maybe (Tuple Int a)
keyToInt tuple = extractFstMaybe $ lmap fromString tuple
  where
    extractFstMaybe :: forall a. Tuple (Maybe Int) a -> Maybe (Tuple Int a)
    extractFstMaybe (Tuple (Just a) b) = Just $ Tuple a b
    extractFstMaybe (Tuple Nothing _) = Nothing

但感觉应该有更 abstract/cleaner 的表达方式。如果我要 extractMaybe 得出一个自然的结论,我可能会创建类似

的东西
-- The typing doesn't really work for this
extractMaybe :: forall a b c d. (Tuple a b) -> Maybe (Tuple c d)
extractMaybe (Tuple (Just a) (Just b)) = Just $ Tuple a b
extractMaybe (Tuple (Just a) b) = Just $ Tuple a b
extractMaybe (Tuple a (Just b)) = Just $ Tuple a b
extractMaybe (Tuple Nothing _) = Nothing
extractMaybe (Tuple _ Nothing) = Nothing
extractMaybe (Tuple a b) = Just $ Tuple a b

在阅读有关应用程序和绑定的内容时,我经常会看到这种重构。我还没有真正将这些课程应用到自己身上的经验。

如果我有一个可能包含 ADT 的结构(Eithers 或 Maybes 或 Arrays 的数组)并且我想定义一种拉动方式那些“out”,是否有一个通用的方法来定义它?


Purescript by Example 有一个函数的这种类型签名的例子:

combineList :: forall f a. Applicative f => List (f a) -> f (List a)

这是做同样的事情,只是为了一个列表。 N 元组使这变得复杂,因为每个元素都可以有不同的类型。如果我在一个元组上调用 extractMaybe,我现在有一个具有任何类型 除了 Maybe 的元组(或者我有 Nothing)。

我可以为 Either 写同样的东西,如果我同时使用两者,我可以知道我有一个任何类型的元组 除了 MaybeEither(或者我有 Nothing)。

我什至不完全确定这是最有帮助的方向。在像 mapMaybe 这样您想过滤掉所有 Nothing 和 [=28] 的情况下,它似乎很有帮助=]s 同时也展开这些类型。

我可以将其编程为:

keyToInt (Tuple a b) = ado
  a' <- fromString a
  in Tuple a' b

因为接近很多类似的需求。您可以轻松地将某些内容应用到 b,或者对 Tuple 以外的内容进行模式匹配,或者将结果与 Tuple 以外的内容相结合。

这正是 ltraverse:

module Main where

import Data.Bitraversable (ltraverse)
import Data.Int (fromString)
import Data.Tuple (Tuple)
import Data.Maybe (Maybe)

keyToInt :: forall a. Tuple String a -> Maybe (Tuple Int a)
keyToInt = ltraverse fromString 

每当你解构一个类型并在另一个类型中重新构建它时(例如 Maybe),这就是你想要 traverse 的时候。在这种情况下,Tuple 有两件事可以遍历,使其成为 Bitraversable。对于此函数,您想要遍历 Tuple 的左侧 - 即 ltraverse.