Перегрузка шоу для списка

Я хочу, чтобы представление, разделенное символом новой строки, вместо обычного, разделенного запятой, для новых типов данных:

newtype SimpleRecord = SimpleRecord ([Char], [Char], Integer)
    deriving (Show)

Я пытался написать этот выпуск Show class:

instance  Show [SimpleRecord] where
        show [(SimpleRecord (n, i, c))] = show (SimpleRecord (n, i, c))++['\n']
        show (l:ls) = (show l)++['\n']++(show ls)

GHC сильно оскорбляет меня.

Может кто-нибудь попытаться объяснить мне, что я могу сделать?

3 ответа

Решение

Во-первых, Show класс должен быть для создания исходного кода на Haskell, который Read Затем класс может читать обратно. Он не предназначен для создания удобного для чтения, "красивого" вывода.

Сказав это, почти каждый злоупотребляет им для последнего, и это может быть полезно для целей отладки.

Итак, ваши варианты:

  1. Напишите некоторую функцию, не вызванную show который делает то, что вы хотите. (Согласно AndrewCкомментарий.)

  2. Использовать showList метод.

Если ты пишешь deriving Show, это говорит компилятору написать все Show методы для вас. Если вы хотите написать их самостоятельно, вам нужно забрать deriving немного первым Тогда вы можете написать свой экземпляр, который будет выглядеть примерно так

instance Show SimpleRecord where
  show (SimpleRecord (x, y, z)) = ...

  showList rs = unlines (map show rs)

Кроме того, если вы еще этого не знали, вы можете написать

mapM_ print records

в приглашении GHCi распечатать любой список печатных вещей с одним элементом в строке.


В качестве последней подсказки, почему

newtype SimpleRecord = SimpleRecord ([Char], [Char], Integer)

скорее, чем

data SimpleRecord = SimpleRecord [Char] [Char] Integer

Возможно, я что-то упустил, но не было понятно, почему вы вводите новый тип (String,String,Integer), а не то, что вам было интересно показать, а именно списки их. Тогда вы избежали бы универсального экземпляра Show для списков:

newtype SimpleRecords = SimpleRecords [(String, String, Integer)]

instance Show SimpleRecords where
  show (SimpleRecords []) = ""
  show (SimpleRecords ((n, i, c): xs)) = 
       show (n, i, c) ++ "\n" ++ show (SimpleRecords xs)

 -- Prelude Main> let a = words "We hold these truths to be self-evident"
 -- Prelude Main> let b = words "All the best people are using Clorox"
 -- Prelude Main> let c = zip3 a b [1::Integer ..]
 -- Prelude Main> SimpleRecords c
 -- ("We","All",1)
 -- ("hold","the",2)
 -- ("these","best",3)
 -- ("truths","people",4)
 -- ("to","are",5)
 -- ("be","using",6)
 -- ("self-evident","Clorox",7)

Ваш вопрос довольно двусмысленный. Если я правильно понимаю, вы пытаетесь изменить значение по умолчанию Show экземпляр для [SimpleRecord],

Поскольку GHC уже определил экземпляр Show [a] когда Show a определено. Вы получаете следующую ошибку (после включения FlexibleInstances расширение) при попытке снова определить экземпляр для Show [SimpleRecord],

Matching instances:
      instance Show a => Show [a] -- Defined in `GHC.Show'
      instance Show [SimpleRecord] -- Defined at show.hs:5:11

Так что вам нужно использовать OverlappingInstances расширение языка, позволяющее перегрузить его. В нем говорится, что GHC соответствует наиболее конкретному случаю.

Вы также можете включить FlexibleInstances расширение, которое позволяет указывать произвольные вложенные типы в объявлении экземпляра.

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverlappingInstances #-}
newtype SimpleRecord = SimpleRecord ([Char], [Char], Integer)
    deriving (Show)

instance  Show [SimpleRecord] where
    show [SimpleRecord (n, i, c)] = show (SimpleRecord (n, i, c))++"\n"
    show (l:ls) = show l ++ "\n" ++ show ls

Вы получите больше информации об этих языковых расширениях в GHC Docs

Просто комментарий к дизайну вашего типа, лучше определить ваш тип как

data SimpleRecord = SimpleRecord String String Integer 

Вы получаете больше гибкости здесь с точки зрения частичного применения конструктора и т. Д.

Другие вопросы по тегам