Haskell中是否可以使用点免模式匹配?

15

给定:

data TwoInts = TwoInts Int Int 

add'em :: TwoInts -> Int
add'em (TwoInts a b) = a+b

是否有可能写出不需要命名abadd'em函数。例如:

 add'em TwoInts = (+) -- (Note: Fails to type check)

2
可能性:是的。明智与否:不一定。 - Dan Burton
2个回答

12

类比元组,

data TwoInts = TwoInts { fst', snd' :: Int }

我们可以定义一个操作,将接受两个参数的函数提升到 TwoInt 上。

uncurry' f p =  f (fst' p) (snd' p)
给我们提供了美好的符号表示:
add'em = uncurry' (+)

你甚至可以为可柯里化的事物创建一个类型类,这样它就不仅适用于TwoInts了... - pat
8
@mathepic,uncurry可以用pointfree的方式来书写。uncurry = ('ap' snd) . (. fst)。关键是要摆脱模式匹配。 - Don Stewart
4
@mathepic,加上这些点更清晰明了,我认为。有一次我听说 Lisp(关于 Lisp 宏)的说法是:你只需要写相同类型的丑陋代码一次。如果您认为具有“点”的代码很“丑陋”,那么只需编写一个“丑陋”的提升函数,然后以后重复使用它即可。 - Dan Burton
4
正如Conor McBride所指出的,常用语/应用函子在这里也有帮助,uncurry f = f <$> fst <*> snd -- 比愚蠢的(.)版本简单得多。 - Don Stewart
我通常将这种东西写成 f . fst <*> snd,因为打字速度更快。在此选择的 Applicative 实例中,<*> 有点像 FORTH 等基于堆栈的语言中的 DUP。 - Robin Green

5
总的来说,我会说不行,这不可能。但是,如果你试图解决在各个地方解包和包装的实际问题(尤其是新类型常见的情况下),我经常定义一个 mapf f (Type val) = Type (f val) 函数,类似于 fmap,然后不导出它。你可以通过传递更多函数来为 n 元数据类型做同样的事情。如果实现不应该是秘密的,你也可以导出它(作为一元的 fmap)。对于复杂类型,我建议使用这种 map 函数或视图,因为模式匹配会将你与实现绑定在一起。
基本类型已经定义了这样的函数,例如 maybeeither

你为什么说这通常是不可能的呢?你总是可以定义构造函数和析构函数来替换显式模式匹配;而且你总是可以将一个指向的 Haskell 函数转换为(任意复杂的)pointfree 版本。因此,一般情况下,它是可能的。 - Don Stewart
只是一个术语问题,我认为他正在寻找一种不需要辅助函数的解决方案。即点无 模式匹配。如果您定义了一个函数,则它是无点函数。拆分构造器最终总是归结为一个情况,对吧?我想您可以说实际上泛型编程意味着您不必编写情况,但这仅因为编译器在自动数据实例中放置了一个情况。 - Evan Laforge
1
“maybe”和“either”实际上是类型的折叠(即使数据类型不是递归的,这可能就是它们没有被称为折叠的原因),因为它将该类型的对象转换为其Church编码:您提供与每个构造函数对应的函数。为了构建返回值,对这些函数的调用替换了对数据类型的构造函数的调用。您的“mapf”与“fmap”非常相似,但仅适用于具有1个参数的1个构造函数的类型;否则,与折叠的类比更有用。 - Blaisorblade

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接