Исправление повторяющихся объявлений экземпляров для типа данных algebrai c - PullRequest
1 голос
/ 31 марта 2020

Допустим, у меня был алгебра c тип данных Building:

data Building 
  = BRestaurant Restaurant 
  | BStore Store 
  | BHouse House 
  ...

Restaurant, Store, House, ... все экземпляры некоторого класса. А пока давайте просто используем Show. В настоящее время я определяю экземпляр Building Show следующим образом:

instance Show Building where 
  show (BRestaurant a) = show a
  show (BStore a)      = show a
  show (BHouse a)      = show a
  ...

Это кажется довольно повторяющимся. Есть ли способ применить функцию show к внутренним данным, зная, что каждый экземпляр элемента отображается и у каждого конструктора есть только один аргумент? Я что-то упускаю, что сделало бы это менее повторяющимся? В идеале я бы получил что-то вроде:

instance Show Building where 
   show a = applyFunctionMagic show a

1 Ответ

7 голосов
/ 31 марта 2020

Звучит как хороший вариант использования для обобщений.

{-# LANGUAGE DeriveGeneric, TypeOperators #-}

import GHC.Generics

Мы хотим реализовать некоторую функцию process для обобщенного типа c:

data Building 
  = BRestaurant Restaurant 
  | BStore Store 
  | BHouse House
  deriving Generic

process :: Building -> String
process = gprocess . from

Для этого, мы определяем следующую gprocess функцию, где мы заменяем тип Building некоторыми параметрами f p:

class GProcess f where
  gprocess :: f p -> String

и реализуем его для конструкторов различных типов, найденных в GH C .Generics.

Мы всегда поднимаем его через M1 (этот экземпляр становится менее тривиальным, когда вам нужен доступ к именам конструктора или поля):

instance GProcess f => GProcess (M1 i c f) where
  gprocess (M1 x) = gprocess x

Мы заинтересованы в обработке типов сумм, которые представлены используя (:+:):

instance (GProcess f, GProcess g) => GProcess (f :+: g) where
  gprocess (L1 x) = gprocess x
  gprocess (R1 y) = gprocess y

Наконец, мы обрабатываем поля с помощью K1:

instance Show a => GProcess (K1 i a) where
  gprocess (K1 x) = show x

И это все для ADT с одним полем на конструктор.

Полный текст: https://gist.github.com/Lysxia/1dd262acbb72231bd4b02b6a8e2fed19


Для получения дополнительной информации о дженериках:

...