自动创建谓词来检测求和类型的成分?

Ign*_*rov 2 haskell algebraic-data-types

我的意思是:

data D = A Int | B String  -- A sum type.

isA, isB :: D -> Bool  -- Component predicates.
isA (A _) = True
isA _     = False
isB (B _) = True
isB _     = False
Run Code Online (Sandbox Code Playgroud)

定义起来很繁琐。当然有更好的方法。一种方法是:

data D = A Int | B String deriving (Typeable, Data)

isA', isB' :: D -> Bool
isA' x = toConstr x == toConstr (A undefined)
isB' x = toConstr x == toConstr (B undefined)
Run Code Online (Sandbox Code Playgroud)

但这需要我提供一个示例值。

有一个技巧可以用“归纳”“折叠”任何数量的变量的函数 ,这使我们定义了一种从任意构造函数获取值的方法:

class C a v where createValue :: a -> v
instance C b D => C (a -> b) D where createValue f = createValue (f undefined)
instance C D D where createValue = id

compareConstructor :: forall a v. (C a v, Data v) => v -> a -> Bool
compareConstructor x c = toConstr x == toConstr (createValue c :: v)
Run Code Online (Sandbox Code Playgroud)

它是这样工作的:

data D = A Int | B String | C Bool Char deriving (Typeable, Data, Show)

? compareConstructor (B "z") (C True)
False
? compareConstructor (C True 'c') C
True
Run Code Online (Sandbox Code Playgroud)

我喜欢这种解决方案,但我想知道是否有更简单的方法来解决这个简单的日常问题。

动机:

我有一个D类型的值列表,大部分用填充A _,并且我需要找出一个B _值是否出现在之前C _ _。我可以通过比较两个findIndex调用来解决此问题,但是我需要对它们进行适当的参数设置。

Li-*_*Xia 6

GHC.Generics是另一种方法。

您可以使用is镜头库中的函数和通用镜头库中的通用棱镜来检查值是否以给定的构造函数开头MyCon

is (_Ctor @"MyCon") myValue
  :: Bool
Run Code Online (Sandbox Code Playgroud)

编译示例:

{-# LANGUAGE DeriveGeneric, TypeApplications, DataKinds #-}

import GHC.Generics
import Data.Generics.Sum
import Control.Lens.Extras

data D = A Int | B String
  deriving Generic

main :: IO ()
main = do
  print $ is (_Ctor @"A") (A 0)   -- True
  print $ is (_Ctor @"A") (B "")  -- False
  print $ is (_Ctor @"B") (A 0)   -- False
  print $ is (_Ctor @"B") (B "")  -- True
Run Code Online (Sandbox Code Playgroud)