【问题标题】:What is the special status of the 2-tuple?2元组的特殊状态是什么?
【发布时间】:2017-06-27 12:15:47
【问题描述】:

阅读 Real World HaskellTypeclassopedia 我得到的印象是 2 元组 (a,b) 在 Haskell 中可以扮演非常特殊的角色。

我遇到的第一个用途是 lookup,我们使用 2 元组列表作为字典。

然后我还发现((,) e) 是函子的一个实例(但没有其他 n 元组),这在上面的(key,value) 示例中是有意义的。

最近的一个案例——我真正想问的那个——在 Typeclassopedia 的第 4.3 章。那里说((,) a)Applicative 的一个实例if a 是一个幺半群。你什么时候真正使用它?您在哪些应用程序中使用了(a,b)Applicative 实例?

【问题讨论】:

  • 哦,情况变得更糟了!对也是Foldable:stackoverflow.com/a/36461185/126014
  • 我认为 2 元组本身并没有那么特殊的地位。关键是通常 2 元组比 3 元组更“适用”。如果你有一个“字典”,那么你可以获得一个键值列表,第三个值在这里没有意义。问题是:如何处理第三个元素。
  • 是的,我明白了,我只是想知道 Applicative 实例有什么用处,因为它要求第一个参数是 Monoid 实例。
  • ((,) a) 应用等价于writer monad
  • @flawr 我不会这么说——基本上所有的 monad 也可以用作单纯的应用程序。只是——出于某种我不知道的原因——Applicative 似乎不如Monad 直观,它的用例也没有Monad 明显。

标签: haskell tuples


【解决方案1】:

没有什么能阻止我们为三元组或任意 n 元组编写实例:

instance Functor ((,,) a b) where
  fmap f (x,y,z) = (x,y,f z)

instance (Monoid a, Monoid b) => Applicative ((,,) a b) where
  pure z              = (mempty,        mempty,          z)
  (a,b,f) <*> (x,y,z) = (a `mappend` x, b `mappend` y, f z)

对并不特殊,因此您可以为任何 n 元组实现实例。但是由于这些实例必须写在某个地方,这就引出了我们应该走多远的问题。例如,Monoid 实例最多定义为 5 个元组。当然可以为 10 元组编写它们,但那时我们只是在复制样板代码。

话虽如此,对是特殊的,因为它们的集合提供了一种描述关系的自然方式。一个例子是字典,它关联了一个术语及其定义:

dictionary :: [(String, String)]
dictionary =
  [("cat", "animal that likes strings; not Strings, though")
  ,("dog", "animal that likes you; yes you")
  ,("foo", "a strange word used by programmers in examples")
  ]

显示这种关系的另一种方式(如果所有对的第一部分都是唯一的)是

partialDictionaryEntry :: String -> String

如果我们将输入域限制为"cat""dog""foo",或者

dictionaryEntry :: String -> Maybe String

这正是\s -&gt; lookup s dictionary 的样子。通过对,您可以对任何其他 n 元组进行建模:

(a,b,z)   = ((a,b),z)
(a,b,c,z) = ((a,b,c),z) = (((a,b),c),z)

从这个意义上说,它们是提供此功能的最小容器。我们可以从对构建所有其他元组类型。哎呀,理论上我们甚至不需要编写 Applicative ((,,) a b) 实例,因为 Monoid 实例已经为 (,) (a,b) 提供了它。

话虽如此,为什么它甚至有一个Applicative 实例?这是最简单的Writer 实现:

log :: (Show a) => a -> (String, a)
log x = (show x ++ "\n", x)

fivePlusThree = (+) <$> log 3 <*> log 5

main = do
  let (logs, result) = fivePlusThree
  putStrLn logs
  print result
3
5

8

这提供了一种向函数或值添加附加信息的简单方法,尽管您可能会使用Writer 及其writer 方法,因为它们更易于使用并提供严格的变体。

【讨论】:

    猜你喜欢
    • 2020-09-13
    • 1970-01-01
    • 2011-07-06
    • 1970-01-01
    • 1970-01-01
    • 2011-05-21
    • 1970-01-01
    • 2019-05-06
    • 2011-05-11
    相关资源
    最近更新 更多