为什么通用函数进程以特殊方式列出头部?
Why generic function process list head in a special way?
我正在开发一个通用函数以根据某些标准从复杂值中删除子值。在这里,我使用包含“z”字母的数据构造函数删除了值。它几乎如我所愿。
> genericFilter (1,[Yez, No])
Just (1,[No])
但是有一种特殊情况,就是整个列表都被丢弃了
如果 Yez 是列表中的第一项。
genericFilter (1,[[Yez, No]])
Just (1,[])
>genericFilter [Yez, No, No]
Nothing
调试后我注意到 :*:
中的问题。
对于:*:
的第一个参数直接使用FilterZ(SomeZ)实例
绕过 FilterZ MetaConst 和 Filter (K1 []),同时对于其余列表
使用了 FilterZ MetaConst 和 Filter(K1[]) 而没有使用 FilterZ(SomeZ)!
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Main where
import Data.Proxy
import GHC.Generics
import GHC.TypeLits
import Data.List
data SomeZ = No | Yez deriving (Show, Eq, Generic)
class FilterZ a where
gfilter :: a x -> Maybe (a x)
instance FilterZ (U1) where
gfilter U1 = Just U1
instance FilterZ (V1) where -- void
gfilter _ = Nothing
instance FilterZ (K1 _1 ()) where
gfilter (K1 ()) = Just $ K1 ()
instance FilterZ (K1 _1 SomeZ) where
gfilter (K1 No) = Just $ K1 No
gfilter (K1 Yez) = Nothing -- Just $ K1 Yez -- Nothing
instance (FilterZ (Rep a), Show a, Generic a) => FilterZ (K1 _1 [a]) where
gfilter (K1 []) = Just $ K1 []
gfilter (K1 (h:r)) = case gfilter (from h) of
Nothing -> gfilter (K1 r)
Just h' -> case gfilter (K1 r) of
Nothing -> Just $ K1 [(to h') :: a] -- Nothing
Just (K1 r') -> Just $ K1 ((to h') : r')
instance FilterZ (K1 _1 Int) where
gfilter (K1 n) = Just $ K1 n
instance FilterZ (K1 _1 Integer) where
gfilter (K1 n) = Just $ K1 n
instance (FilterZ a, FilterZ b) => FilterZ (a :+: b) where
gfilter (L1 x) = case gfilter x of
Nothing -> Nothing
Just x' -> Just $ L1 x'
gfilter (R1 x) = case gfilter x of
Nothing -> Nothing
Just x' -> Just $ R1 x'
instance (FilterZ a, FilterZ b) => FilterZ (a :*: b) where
gfilter (a :*: b) =
case gfilter a of
Nothing -> Nothing
Just a' -> case gfilter b of
Nothing -> Nothing
Just b' -> Just $ a' :*: b'
instance FilterZ c => FilterZ (M1 a ('MetaData dname mname pname isnewtype) c) where
gfilter (M1 x) = case gfilter x of
Nothing -> Nothing
Just x' -> Just $ M1 x'
instance (KnownSymbol dcn, FilterZ c) => FilterZ (M1 a ('MetaCons dcn p f) c) where
gfilter (M1 x) = case find (=='z') name of
Just _ -> Nothing
Nothing -> case gfilter x of
Nothing -> Nothing
Just x' -> Just $ M1 x'
where
name = symbolVal (undefined :: Proxy dcn)
instance FilterZ c => FilterZ (M1 a ('MetaSel fsel packness stricnesss lazines) c) where
gfilter (M1 x) = case gfilter x of
Nothing -> Nothing
Just x' -> Just $ M1 x'
genericFilter :: (Generic a, FilterZ (Rep a)) => a -> Maybe a
genericFilter a = fmap to $ gfilter (from a)
函数from
仅在顶层工作。因此,如果您将 from
应用于列表,您将获得它的通用表示,它是其头部和尾部的单位或乘积:
*Gen> from [Yez, No]
M1 {unM1 = R1 (M1 {unM1 = M1 {unM1 = K1 {unK1 = Yez}} :*: M1 {unM1 = K1 {unK1 = [No]}}})}
请注意,头部是分开的,但 [No]
没有进一步分解。因此,如果您的列表不在顶层,它永远不会像这样在 from
:
下分解
*Gen> from (1, [Yez, No])
M1 {unM1 = M1 {unM1 = M1 {unM1 = K1 {unK1 = 1}} :*: M1 {unM1 = K1 {unK1 = [Yez,No]}}}}
请注意列表 [Yez, No]
保持不变。
第一种情况genericFilter
穿过M1
到达:*:
。产品的第一个组件是 Yez
,因此通过 FilterZ (K1 _1 SomeZ)
实例它被映射到 Nothing
。 (FilterZ a, FilterZ b) => FilterZ (a :*: b)
实例表示最终结果应该是 Nothing
.
在第二种情况下,再次 genericFilter
穿过 M1
并到达 :*:。这次第一个组件是一个单元,它被映射到 unit,第二个组件是 [SomeZ]
类型,它被 (FilterZ (Rep a), Show a, Generic a) => FilterZ (K1 _1 [a])
实例过滤。
我正在开发一个通用函数以根据某些标准从复杂值中删除子值。在这里,我使用包含“z”字母的数据构造函数删除了值。它几乎如我所愿。
> genericFilter (1,[Yez, No])
Just (1,[No])
但是有一种特殊情况,就是整个列表都被丢弃了 如果 Yez 是列表中的第一项。
genericFilter (1,[[Yez, No]])
Just (1,[])
>genericFilter [Yez, No, No]
Nothing
调试后我注意到 :*:
中的问题。
对于:*:
的第一个参数直接使用FilterZ(SomeZ)实例
绕过 FilterZ MetaConst 和 Filter (K1 []),同时对于其余列表
使用了 FilterZ MetaConst 和 Filter(K1[]) 而没有使用 FilterZ(SomeZ)!
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Main where
import Data.Proxy
import GHC.Generics
import GHC.TypeLits
import Data.List
data SomeZ = No | Yez deriving (Show, Eq, Generic)
class FilterZ a where
gfilter :: a x -> Maybe (a x)
instance FilterZ (U1) where
gfilter U1 = Just U1
instance FilterZ (V1) where -- void
gfilter _ = Nothing
instance FilterZ (K1 _1 ()) where
gfilter (K1 ()) = Just $ K1 ()
instance FilterZ (K1 _1 SomeZ) where
gfilter (K1 No) = Just $ K1 No
gfilter (K1 Yez) = Nothing -- Just $ K1 Yez -- Nothing
instance (FilterZ (Rep a), Show a, Generic a) => FilterZ (K1 _1 [a]) where
gfilter (K1 []) = Just $ K1 []
gfilter (K1 (h:r)) = case gfilter (from h) of
Nothing -> gfilter (K1 r)
Just h' -> case gfilter (K1 r) of
Nothing -> Just $ K1 [(to h') :: a] -- Nothing
Just (K1 r') -> Just $ K1 ((to h') : r')
instance FilterZ (K1 _1 Int) where
gfilter (K1 n) = Just $ K1 n
instance FilterZ (K1 _1 Integer) where
gfilter (K1 n) = Just $ K1 n
instance (FilterZ a, FilterZ b) => FilterZ (a :+: b) where
gfilter (L1 x) = case gfilter x of
Nothing -> Nothing
Just x' -> Just $ L1 x'
gfilter (R1 x) = case gfilter x of
Nothing -> Nothing
Just x' -> Just $ R1 x'
instance (FilterZ a, FilterZ b) => FilterZ (a :*: b) where
gfilter (a :*: b) =
case gfilter a of
Nothing -> Nothing
Just a' -> case gfilter b of
Nothing -> Nothing
Just b' -> Just $ a' :*: b'
instance FilterZ c => FilterZ (M1 a ('MetaData dname mname pname isnewtype) c) where
gfilter (M1 x) = case gfilter x of
Nothing -> Nothing
Just x' -> Just $ M1 x'
instance (KnownSymbol dcn, FilterZ c) => FilterZ (M1 a ('MetaCons dcn p f) c) where
gfilter (M1 x) = case find (=='z') name of
Just _ -> Nothing
Nothing -> case gfilter x of
Nothing -> Nothing
Just x' -> Just $ M1 x'
where
name = symbolVal (undefined :: Proxy dcn)
instance FilterZ c => FilterZ (M1 a ('MetaSel fsel packness stricnesss lazines) c) where
gfilter (M1 x) = case gfilter x of
Nothing -> Nothing
Just x' -> Just $ M1 x'
genericFilter :: (Generic a, FilterZ (Rep a)) => a -> Maybe a
genericFilter a = fmap to $ gfilter (from a)
函数from
仅在顶层工作。因此,如果您将 from
应用于列表,您将获得它的通用表示,它是其头部和尾部的单位或乘积:
*Gen> from [Yez, No]
M1 {unM1 = R1 (M1 {unM1 = M1 {unM1 = K1 {unK1 = Yez}} :*: M1 {unM1 = K1 {unK1 = [No]}}})}
请注意,头部是分开的,但 [No]
没有进一步分解。因此,如果您的列表不在顶层,它永远不会像这样在 from
:
*Gen> from (1, [Yez, No])
M1 {unM1 = M1 {unM1 = M1 {unM1 = K1 {unK1 = 1}} :*: M1 {unM1 = K1 {unK1 = [Yez,No]}}}}
请注意列表 [Yez, No]
保持不变。
第一种情况genericFilter
穿过M1
到达:*:
。产品的第一个组件是 Yez
,因此通过 FilterZ (K1 _1 SomeZ)
实例它被映射到 Nothing
。 (FilterZ a, FilterZ b) => FilterZ (a :*: b)
实例表示最终结果应该是 Nothing
.
在第二种情况下,再次 genericFilter
穿过 M1
并到达 :*:。这次第一个组件是一个单元,它被映射到 unit,第二个组件是 [SomeZ]
类型,它被 (FilterZ (Rep a), Show a, Generic a) => FilterZ (K1 _1 [a])
实例过滤。