>

모든 TypeRep 의 목록을 얻는 방법이 있습니까 일반 프로그래밍을 사용하여 가치 안에 있습니까?

예를 들어, 함수를 정의 할 수 있을까요 :

typeReps :: (Data a, Typeable a) => a -> [TypeRep]

그런 식으로 :

>>> typeReps (1 :: Int, 'a')
[(Int, Char), Int, Char]
>>> typeReps (Foo ['a', 'b'])
[Foo, [Char], Char, Char]

내가 시도했다

{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE RankNTypes #-}
module Example where
import Data.Data
import Data.Typeable
typeReps :: (Data a, Typeable a) => a -> TypeReps a
typeReps a = gfoldl step fcstr a
  where
    step :: forall d b. (Typeable d, Data d) =>  TypeReps (d -> b) -> d -> TypeReps b
    step tot d = tot <++> typeReps d
    fcstr :: forall g . g -> TypeReps g
    fcstr g  = TypeReps [typeOf a]

그러나 이것이 TypeRep 유형을 복제하는 것처럼 보입니다. s 결과 :

>>> typeReps ['a']
TypeReps {getTypes = [[Char],Char,[Char]]}

또한, 나는 g 를 사용하지 않는 것이 약간 뒤로 보입니다.  그러나 a   fsctr 에서  위의 기능 (그리고 g 를 제한 할 수 없기 때문에 나는 할 수 없다  와이즈 비즈 ).

이것이 이런 식으로 해결할 수 있는지 모르겠습니다. 그렇지 않다면 다른 방법이 있는지 궁금합니다.

Typeable

  • 답변 # 1

    의견에서 제안한 것처럼 [1,2,3] 를 고려하지 않은 것 같습니다.  실제로 1 : 2 : 3 : [] 입니다  (여기서꼬리 하위 용어에는 [Int] 유형이 있습니다. ). 목록에 특별한 경우를 추가 할 수 있습니다.

    {-# LANGUAGE ViewPatterns #-}
    import Data.Data
    -- | Returns 'Just' only for lists
    --
    -- This can surely be done more efficiently, but it does the job.
    listTypeReps :: Data a => a -> Maybe [TypeRep]
    listTypeReps x
      | typeRepTyCon (typeOf x) == listTyCon
      , toConstr x == toConstr ([] :: [()])   -- empty list
      = Just []
      | typeRepTyCon (typeOf x) == listTyCon
      , toConstr x == toConstr [()]           -- cons
      , [headTs, _] <- gmapQ typeReps x
      , [_, Just tailTs] <- gmapQ listTypeReps x
      = Just (headTs ++ tailTs)
      | otherwise
      = Nothing
    listTyCon :: TyCon
    listTyCon = typeRepTyCon (typeOf ([] :: [()]))
    -- | Get the types of subterms
    typeReps :: Data a => a -> [TypeRep]
    typeReps x = typeOf x : case listTypeReps x of
                              Just ts -> ts
                              Nothing -> concat (gmapQ typeReps x)
    
    

    시도해보십시오 :

    ghci> :set -XDeriveDataTypeable
    ghci> data Foo = Foo [Int] (Char,Char) deriving (Data,Typeable)
    ghci> typeReps $ Foo [1, 2] ('a', 'b')
    [Foo,[Int],Int,Int,(Char,Char),Char,Char]
    
    

  • 답변 # 2

    도움을 주셔서 감사합니다! 누군가 Generics 를 사용 하여이 문제를 해결하는 데 관심이있는 경우 이 메커니즘으로 찾은 솔루션은 다음과 같습니다.

    class Typeable a => HasTypeReps a where
      typeReps :: a -> [TypeRep]
      default typeReps :: (Generic a, GHasTypeReps (Rep a)) => a -> [TypeRep]
      typeReps a = typeOf a: gTypeReps (from a)
    class GHasTypeReps f where
      gTypeReps :: f a -> [TypeRep]
    instance GHasTypeReps U1 where
      gTypeReps U1 = []
    instance (GHasTypeReps a, GHasTypeReps b) => GHasTypeReps (a :*: b) where
      gTypeReps (a :*: b) = gTypeReps a ++ gTypeReps b
    instance (GHasTypeReps a, GHasTypeReps b) => GHasTypeReps (a :+: b) where
      gTypeReps (L1 a) = gTypeReps a
      gTypeReps (R1 b) = gTypeReps b
    -- | We do need to do anything for the metadata.
    instance (GHasTypeReps a) => GHasTypeReps (M1 i c a) where
        gTypeReps (M1 x) = gTypeReps x
    -- | And the only interesting case, get the type of a type constructor
    instance (HasTypeReps a) => GHasTypeReps (K1 i a) where
        gTypeReps (K1 x) = typeReps x
    instance HasTypeReps a => HasTypeReps [a] where
      typeReps xs = typeOf xs: concatMap typeReps xs
    instance (HasTypeReps a, HasTypeReps b) => HasTypeReps (a, b) where
      typeReps t@(a, b) = typeOf t: (typeReps a ++ typeReps b)
    instance HasTypeReps Char where
      typeReps x = [typeOf x]
    instance HasTypeReps Int where
      typeReps x = [typeOf x]
    
    
    

    다른 답변에서 지적했듯이 Li-yao는 특별한 방법으로 목록을 처리하고 몇 가지 다른 인스턴스를 정의하여 보일러 플레이트를 추가해야합니다.

    예 :

    >>> typeReps ['a']
    [[Char],Char]
    >>> :set -XDeriveGeneric
    >>> data Foo = Foo [Int] (Char, Char) deriving (Generic)
    >>> instance HasTypeReps Foo
    >>> typeReps $ Foo [1, 2] ('a', 'b')
    [Foo,[Int],Int,Int,(Char,Char),Char,Char]
    
    

관련 자료

  • 이전 java - 도트 대신 쉼표로 이중 허용
  • 다음 google bigquery - Select 문에 일부 열에 CONCAT 기능이있는 경우 SQL 문은 어떤 순서로 실행됩니까?