我的代码中有一堆错综复杂的数据构造函数,我想在新的模式同义词
语言扩展的帮助下对其进行一些整理。然而,在我看来,如果没有专门的 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/