Достъп до шоуто по подразбиране в Haskell?

Да кажем, че имате структура от данни (заимствана от този въпрос):

data Greek = Alpha | Beta | Gamma | Delta | Eta | Number Int

Сега човек може да го направи екземпляр на Show, като добави deriving Show към тази инструкция.

Кажете обаче, че искаме да покажем Number Int като:

instance Show Greek where
    show (Number x) = show x
    -- ...

Проблемът е, че трябва да посочите всички останали части от Greek данните, както и като:

    show Alpha = "Alpha"
    show Beta = "Beta"

За този малък пример това разбира се е възможно. Но ако броят на опциите е дълъг, това изисква голямо количество работа.

Чудя се дали е възможно да осъществя достъп до изпълнението на „показване по подразбиране“ и да го извикам със заместващ знак. Например:

instance Show Greek where
    show (Number x) = show x
    show x = defaultShow x

По този начин вие „внедрявате“ специфичните модели, които се различават от подхода по подразбиране, а останалите модели се разрешават от „резервния механизъм“.

Нещо малко подобно на замяна на метод с препратка към super.method в обектно-ориентираното програмиране.


person Willem Van Onsem    schedule 23.02.2015    source източник
comment
Разбира се, просто използвайте обвивка newtype като в почти правилния, но изтрит отговор.   -  person Thomas M. DuBuisson    schedule 23.02.2015
comment
Правилният начин да направите това е да имате .. deriving Show и след това да имате някакъв красив клас за печат (или просто функция), който показва данните както искате. Също така, няма такова нещо като замяна на метод в Haskell, или super.method, защото в Haskell няма подвъвеждане.   -  person user2407038    schedule 23.02.2015
comment
Предполага се, че функцията show генерира низ, съдържащ Haskell израз, който, след като бъде оценен, връща първоначалната стойност. Ако имате нужда от нещо друго, трябва да декларирате различна функция (евентуално в нейния собствен клас).   -  person chi    schedule 23.02.2015
comment
@chi: тогава (a) защо може да бъде отменен (може да се направи функция, дефинирана върху обектите) и (b) защо безкрайните списъци са свити в литерал на масив?   -  person Willem Van Onsem    schedule 23.02.2015
comment
(a) защото понякога конструкторите не се експортират, така че трябва да го замените (вижте напр. Data.Set) (b) Не разбирам напълно гледната ви точка, но бихте били прави да кажете, че договорът е нарушен за безкрайни списъци напр. read (show [[1..],[2]]) няма да получи оригиналния списък обратно. Като се има предвид това, вярно е, че договорът често се нарушава в кода на приложението, така че това, което се опитвате да направите, не е необичайно. Понякога е доста удобно просто да замените show, за да бъдете по-четими и да забравите синтаксиса на Haskell.   -  person chi    schedule 23.02.2015
comment
Но дори когато show не произвежда валиден синтаксис на Haskell, той все още обикновено се счита за ориентиран към програмиста. Покажи ми да бъде текстово представяне на данните, за да мога да разбера какво е, не показва тази стойност като текст за крайния потребител. От гледна точка на Python това е repr, а не str. Така че показването на някои Greek стойности по начин, който е неразличим от цели числа, е малко миризма на код.   -  person Ben    schedule 22.12.2015
comment
Ето защо ще намерите толкова много въпроси на SO за това как да накарате show да рендира String стойности без кавички или списъци без скоби. Твърде много стандартни екземпляри третират show като извеждащ код, за да може наистина лесно да се използва за показване.   -  person Ben    schedule 22.12.2015


Отговори (3)


Можете да постигнете това като използвате Data и Typeable. Разбира се, това е хак и този пример работи само за "изброени" типове, както във вашия пример.

Сигурен съм, че бихме могли да разберем по-подробно как правим това, но за да покрием дадения от вас пример:

{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data
import Data.Typeable

data Greek = Alpha | Beta | Gamma | Delta | Eta | Number Int 
             deriving (Data,Typeable)

instance Show Greek where
    show Number n = show n
    show x = show $ toConstr x

Този подход, както го внедрих, не може да се справи с вложени структури от данни или нещо друго, което е малко фантастично, но отново, това е грозен хак. Ако наистина трябва да използвате този подход, можете да се разровите в пакета Data.Data, сигурен съм, че можете да сглобите нещо...

Ето публикация в блог, даваща кратко въведение в пакетите: http://chrisdone.com/posts/data-typeable

Правилният начин да направите това е да използвате newtype обвивка. Осъзнавам, че това все пак не е най-удобното решение, особено когато се използва GHCi, но не налага допълнителни разходи и е по-малко вероятно да се счупи по неочакван начин, докато програмата ви расте.

data Greek = Alpha | Beta | Gamma | Delta | Eta | Number Int 
         deriving (Show)

newtype SpecialPrint = SpecialPrint Greek

instance Show SpecialPrint where
    show (SpecialPrint (Number x)) = "Number: " ++ show x
    show (SpecialPrint x) = show x

main = do
    print (SpecialPrint Alpha)
    print (SpecialPrint $ Number 1)
person danem    schedule 23.02.2015
comment
Мисля, че бихте могли да постигнете нещо подобно на първия вариант, като използвате generic-deriving, което вероятно ще обработва и вложени неща (стига всичко да е Generic). - person phipsgabler; 23.02.2015

Както @phg посочи по-горе в коментара, това може да се направи и с помощта на generic-deriving:

{-# LANGUAGE DeriveGeneric #-}
module Main where

import           Generics.Deriving.Base (Generic)
import           Generics.Deriving.Show (GShow, gshow)

data Greek = Alpha | Beta | Gamma | Delta | Eta | Number Int
  deriving (Generic)

instance GShow Greek
instance Show Greek where
  show (Number n) = "n:" ++ show n
  show l = gshow l

main :: IO ()
main = do
  print (Number 8)
  print Alpha
person paluh    schedule 13.02.2016

Не, това не е възможно AFAIK.

Освен това персонализираните екземпляри на Show заслужават втори размисъл, тъй като Show и Read екземплярите трябва да са взаимно съвместими.

За просто конвертиране в човешки (или който и да е) четими низове, използвайте своя собствена функция или собствен типов клас. Това също ще постигне това, което искате:

Ако приемем, че имате Presentable типклас с метод present, а също и екземпляра по подразбиране Show, можете да напишете:

instance Presentable Greek where
    present (Number x) = show x
    present x = show x
person Abhay    schedule 23.02.2015