haskell 有没有可能以无点形式写出模式匹配函数?

v7pvogib  于 2022-11-14  发布在  其他
关注(0)|答案(3)|浏览(147)

考虑下面的Haskell代码。

data Keypress = Keypress Int Char

getSeq :: Keypress -> [Char]
getSeq (Keypress i c) = replicate i c

有没有办法以无点形式写getSeq

getSeq的定义和它的模式匹配非常相似,似乎可以使用currying或monads之类的方法来避免指定ic参数。但是,pointfree.io不能解析getSeq的无点输出,我认为是由于模式匹配。
这可能吗?

jdzmm42g

jdzmm42g1#

定义一个catamorphism通常是有用的,尤其是对于具有多个构造函数的递归数据类型,这是一种在为每个可能的构造函数给定一个函数时折叠数据结构的方法。
例如,对于Bool,变质作用为

bool :: a -> a -> Bool -> a
bool x _ False = x
bool _ y True = y

且对于Either,它是

either :: (a -> c) -> (b -> c) -> Either a b -> c
either f _ (Left x) = f x
either _ g (Right x) = g x

更高级的退化是列表的退化,你可能以前见过:foldr

foldr :: (a -> b -> b) -> b -> [a] -> b
foldr f init [] = init
foldr f init (x:xs) = f x (foldr f init xs)

我们通常不会这么想(至少我不会),但foldr是一种退化:只要您为[a]的两个构造函数中找到的值提供“处理程序,”它就可以处理模式匹配和递归地解构列表:

  • 处理[]的一种情况,根本不需要参数:只有b类型的值
  • 一个处理(x:xs)的案例。这个案例采用一个参数表示x,即列表的头部,还有一个参数表示递归折叠尾部的结果,即b类型的值。

对于只有一个构造函数的类型,退化就不那么令人兴奋了,但是我们可以很容易地为Keypress类型定义一个构造函数:

key :: (Int -> Char -> a) -> Keypress -> a
key f (Keypress x c) = f x c

在某种程度上,退化允许您抽象出函数定义的模式匹配部分,之后您可以只使用那些不再需要直接接触底层数据类型的函数。
定义了一次通用函数之后,您可以多次使用它,以实现您所希望的任何无点函数。

getSeq :: Keypress -> [Char]
getSeq = key replicate
gz5pxeao

gz5pxeao2#

正如所写的,没有。但如果你愿意,你可以修复它:

data Keypress = Keypress
  { count :: Int
  , char :: Char }

然后

getSeq p = replicate (count p) (char p)

并且可以被转换成

getSeq = replicate <$> count <*> char
cclgggtu

cclgggtu3#

如果没有一点样板文件,您就无法做到这一点,但是lens可以为您生成样板文件,所以这可能是您将获得的最接近的结果。
Control.Lens.TH使用makePrisms将生成一个Iso,它本质上是单构造函数数据类型上的一级模式匹配。方便的是,Iso是双向的,所以你可以对它们执行view(取出值,就像模式匹配一样)和review(把值放回,就像正常使用构造函数一样)。
使用makePrismsview,可以用无点的方式写getSeq

{-# LANGUAGE TemplateHaskell #-}
import Control.Lens

data Keypress = Keypress Int Char
makePrisms ''Keypress

getSeq :: Keypress -> [Char]
getSeq = uncurry replicate . view _Keypress

这样更好吗?我不知道。代码中的模式匹配在我看来很好,但是如果你已经在使用lens,这个版本可能更适合你。

相关问题