haskell - 我可以在数据构造函数内将 View 模式转换到数据上吗?

标签 haskell

我的代码中有一堆错综复杂的数据构造函数,我想在新的模式同义词语言扩展的帮助下对其进行一些整理。然而,在我看来,如果没有专门的 View 函数来剥离手头的特定数据构造函数,而只是将一些常用的库函数应用于内部数据,我就无法做到这一点。我希望我可以针对构造函数进行模式匹配,然后将常用的库函数应用为 View ,从而无需显式定义专门的 View 函数。唉,我不知道该怎么做。

编写专门的 View 函数的不太明显的缺点是,如果模式匹配失败,则会出现一个错误,提及 View 函数的名称,从而破坏模式同义词的抽象。因此,我不能只是在 View 函数中出现模式匹配失败,而是必须显式返回 Maybe 值,这样我就无法在模式本身中匹配 Just。这正是样板文件。

对于在这种情况下如何最好地安排代码的任何评论,包括以这种方式使用模式同义词是否实际上是一个好的做法,我将不胜感激。

这是我专门针对这个问题编写的示例代码,与我实际必须编写的代码非常相似。我尽力做到简洁。我还到处都放了评论和例子——我希望它对读者有帮助,而不是让读者烦恼。您还可以立即在 ghci 中运行代码。

{-# LANGUAGE
    PatternSynonyms
  , ViewPatterns
  #-}

module PatternSynonym where


-- ### Type definitions.

-- | This wrapper may have been introduced to harden type safety, or define a
--   typeclass instance. Its actual purpose does not matter for us here.
newtype Wrapped a = Wrap { unWrap :: a } deriving (Eq, Show)

-- | This data type exemplifies a non-trivial collection of things.
data MaybeThings a = Some [a] | None deriving (Eq, Show)

-- | This type synonym exemplifies a non-trivial collection of things that are
--   additionally wrapped.
type MaybeWrappedThings a = MaybeThings (Wrapped a)


-- ### An example of what we may want to do with our types:

-- | This is a function that does useful work on plain (not Wrapped!) Ints.
doSomething :: [Int] -> [Int]
doSomething = filter even
-- ^
--   λ doSomething [2, 3, 5]
--   [2]

-- | This is the example data we may have.
example :: MaybeWrappedThings Int
example = Some [Wrap 2, Wrap 3, Wrap 5]

-- | This is a function that must only accept a collection of wrapped things,
--   but it has to unwrap them in order to do something useful.
getThings :: MaybeWrappedThings Int -> [Int]
getThings (Some wxs) = doSomething xs
  where xs = unWrap <$> wxs
getThings None       = [ ]
-- ^
--   λ getThings example
--   [2]


-- ### An example of how we may simplify the same logic with the help of
--   pattern synonyms.

-- | This helper function is necessary (?) in order for it to be possible to
--   define the pattern synonym.
unWrapAll :: MaybeWrappedThings a -> Maybe [a]
unWrapAll (Some wxs) = Just (unWrap <$> wxs)
unWrapAll None = Nothing

-- | This is the pattern synonym that allows us to somewhat simplify getThings.
pattern Some' :: [a] -> MaybeWrappedThings a
pattern Some' xs <- (unWrapAll -> Just xs)
  where Some' = Some . fmap Wrap

-- | This is how we may define our data with the pattern synonym.
--   It's got linearly less lexemes!
example' :: MaybeWrappedThings Int
example' = Some' [2, 3, 5]
-- ^
--   λ example == example'
--   True

-- | This is how our function may look with the pattern synonym.
getThings' :: MaybeWrappedThings Int -> [Int]
getThings' (Some' xs) = doSomething xs
getThings' None       = [ ]
-- ^
--   λ getThings' example'
--   [2]
--
--   λ getThings' example' == getThings example
--   True

最佳答案

有什么 Haskell 不能做的事情吗?

我认为:

pattern Some' xs <- Some (coerce -> xs)

-- 就是完美。

感谢@chi 提供的coerce 功能,感谢@li-yao-xia 提供的在与Some 数据构造函数匹配后查看变量的代码。

这非常直观,我只是没想到 Haskell 能做到这么多。

关于haskell - 我可以在数据构造函数内将 View 模式转换到数据上吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48677751/

相关文章:

haskell - 了解 Hindley-Milner 类型推断中的多型

haskell - 如何在reactive-banana中实现游戏循环?

haskell - 相当于mapM的箭头?

windows - Haskell removeDirectoryRecursive : permission denied on Windows

haskell - Haskell 中的交换函数

Haskell:如何捕获键盘按下,如上、下、左、右

Haskell 无法从上下文中推导出 (t ~ t1) (框架 t)

haskell - 如何在 Haskell 中过滤列表?

Haskell 图双线箭头

haskell - 为什么 `do` block 中的类型在下一行匹配,但在同一行不匹配?