在Haskell中使用泛型列出构造函数名称

时间:2018-08-14 19:32:43

标签: haskell

我知道如何通过以下方式列出构造函数名称:

{-# LANGUAGE DeriveGeneric        #-}
{-# LANGUAGE FlexibleContexts     #-}
{-# LANGUAGE FlexibleInstances    #-}
{-# LANGUAGE PolyKinds            #-}
{-# LANGUAGE ScopedTypeVariables  #-}
{-# LANGUAGE TypeApplications     #-}
{-# LANGUAGE TypeOperators        #-}

module Generics where     

import           Data.Proxy          
import           GHC.Generics        

class Names' f where
  names' :: Proxy f -> [String]
instance (Names' f) => Names' (M1 D t f) where
  names' _ = names' (Proxy :: Proxy f)
instance (Names' f, Names' g) => Names' (f :+: g) where
  names' _ = (names' (Proxy :: Proxy f) ++ (names' (Proxy :: Proxy g)))
instance (Constructor c) => Names' (C1 c f) where
  names' _ = [conName (undefined :: C1 c f g)]

data Test = Foo | Bar Int | Baz { x :: Int } deriving (Generic)

main :: IO ()
main = do
  print $ names' (Proxy :: Proxy (Rep Test))
--> ["Foo", "Bar", "Baz"]

但是在那种情况下,我们需要一个Proxy (Rep Test)。如何使用给定的Proxy Test做同样的事情?

我发现了一个example如何获取记录的第一个选择器,但不知道如何解决我的问题。请帮忙。

2 个答案:

答案 0 :(得分:2)

简单:

{-# LANGUAGE ScopedTypeVariables, FlexibleContexts #-}
names :: forall t. (Generic t, Names' (Rep t)) => Proxy t -> [String]
names _ = names' (Proxy :: Proxy (Rep t))

之所以起作用,是因为Proxy是无关紧要的:只要您可以命名类型,就可以为其构建Proxy。 (旁注:除非您使用的是GHC <8,否则您应该在AllowAmbiguousTypes上使用TypeApplicationsProxy扩展名。在GHC> = 8上,您唯一需要{{ 1}}之类的东西是在较高等级的环境中。)

您可能还会说

Proxy

要为{-# LANGUAGE ScopedTypeVariables, FlexibleContexts, UndecidableInstances #-} class (Generic t, Names' (Rep t)) => Names t where names :: Proxy t -> [String] instance (Generic t, Names' (Rep t)) => Names t where names _ = names' (Proxy :: Proxy (Rep t)) 获得一个不错的约束同义词Names t

答案 1 :(得分:1)

您可以使用Data.Data

jQuery(document).ready(function() {

    // An array of dates
    var eventDates = {};
    eventDates[ new Date( '12/08/2018' )] = new Date( '12/08/2018' );
    eventDates[ new Date( '12/06/2014' )] = new Date( '12/06/2014' );
    eventDates[ new Date( '12/20/2014' )] = new Date( '12/20/2014' );
    eventDates[ new Date( '12/25/2014' )] = new Date( '12/25/2014' );

    // datepicker
    jQuery('#datepicker').datepicker({
        beforeShowDay: function( date ) {
            var highlight = eventDates[date];
            if( highlight ) {
                 return [true, "event", highlight];
            } else {
                 return [true, '', ''];
            }
         }
    });
});

现在,您可以使用{-# language DerivingDataTypeable #-} import Data.Data import Data.Typeable data Test = ... deriving (Data, Typeable) 来获取代表您的ADT的类型dataTypeOf的值(例如DataType)。

然后dataTypeOf (undefined :: Test)将为您提供dataTypeConstrs(构造函数)的列表。

然后在每个Constr上打印名称。