Data.Text проти String


80

Хоча загальна думка спільноти Haskell така, що завжди краще використовувати Textзамість цього String, той факт, що все-таки API більшості підтримуваних бібліотек Stringорієнтований, мене бентежить. З іншого боку, є помітні проекти , які Stringвзагалі розглядаються як помилки і забезпечують Preludeусі екземпляри String-орієнтованих функцій, замінених на Text-подібні.

Тож чи існують причини для людей продовжувати писати Stringорієнтовані API, крім зворотної та стандартної сумісності Prelude та "інтерті, що робить перемикання"? Чи є якісь інші недоліки Textпорівняно з String?

Зокрема, мене це цікавить, оскільки я розробляю бібліотеку і намагаюся вирішити, який тип використовувати для висловлення повідомлень про помилки.


Наскільки важко буде підтримати обох?
Даніель Вагнер,

6
@Vektorweg Я б сперечався. Оскільки Stringце просто псевдонім для списку Chars, цілком природно, що він має різні робочі характеристики, ніж монолітні дані, що Textє. Обидва типи взагалі не турбують компілятор, оскільки вони не є примітивними і визначаються в бібліотеках.
Микита Волков

1
@DanielWagner Хіба це не виявиться не надто вмотивованим ускладненням? У будь-якому випадку, питання полягає в загальному підході, якби існувала спільна модель підтримки обох типів у бібліотеках, яка була б значною.
Микита Волков

3
@Vektorweg Є хороша публікація в блозі про Досить розумний компілятор . (Я щойно зрозумів, що в ньому згадується також GHC.)
kqr

1
Йдіть за текстом! Майбутні покоління одного разу можуть отримати вигоду з світу без рядків, якщо ми припинимо додавати рядовий код.
Titou

Відповіді:


31

Моя безпідставна здогадка полягає в тому, що більшість авторів бібліотек не хочуть додавати більше залежностей, ніж потрібно. Оскільки рядки є частиною буквально кожного дистрибутива Haskell (це частина мовного стандарту!), Набагато легше бути прийнятим, якщо ви використовуєте рядки і не вимагаєте, щоб ваші користувачі сортували текстові розподіли від злому.

Це одна з тих "помилок у дизайні", з якою вам просто потрібно жити, якщо ви не зможете переконати більшість спільноти перейти на ніч. Просто подивіться, скільки часу потрібно, щоб Applicative став суперкласом Monad - відносно незначної, але дуже бажаної зміни - і уявіть, скільки часу знадобилося б, щоб замінити всі String-речі на Text.


Щоб відповісти на ваше більш конкретне запитання: я б пішов із String, якщо ви не отримаєте помітних переваг у продуктивності, використовуючи Text. Повідомлення про помилки зазвичай є досить дрібними одноразовими речами, тому використовувати String не повинно бути великою проблемою.

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


* Я вкладаю дизайнерські помилки в відлякувальні лапки, оскільки рядки як список-символів - це чудова властивість, яка полегшує їх міркування та інтеграцію з іншими існуючими функціями, що працюють зі списком.


4
Йдеться не стільки про якусь фанатичну чистоту, просто я волів би зробити внесок у перехід на краще (якщо він справді такий), а не про стагнацію неоптимальних підходів. Гаразд, ви підтверджуєте, що по суті немає жодних недоліків використання тексту?
Микита Волков

4
@NikitaVolkov Якщо ви хочете внести свій внесок у перехід, я думаю, ви можете зробити більші зміни, залучивши себе до процесу оновлення стандарту та лобіювання / перетворення існуючих бібліотек. Практично відсутні недоліки, крім тих, про які ви можете придумати, наприклад, частота усиновлення та люди, які хочуть збігатись на першій букві або використовувати карту з Data.List тощо.
kqr

6
Це може бути вже не так вже й важливо, оскільки Data.Text на сьогоднішній день є майже даним і виходить з коробки з GHC (яким, я вважаю, більшість людей користуються в наші дні).
Profpatsch

23

Якщо ваш API націлений на обробку великої кількості символьно-орієнтованих даних та / або різних кодувань, тоді ваш API повинен використовувати текст .

Якщо ваш API насамперед призначений для роботи з невеликими одноразовими рядками, то використання вбудованого типу String має бути нормальним.

Використання рядка для великих обсягів тексту змусить програми, що використовують ваш API, споживати значно більше пам'яті. Використання його з іноземними кодуваннями може серйозно ускладнити використання залежно від того, як працює ваш API.

Рядок є досить дорогим (принаймні 5N слів, де N - кількість символів у рядку). Слово - це така ж кількість бітів, що і архітектура процесора (наприклад, 32 біти або 64 біти): http://blog.johantibell.com/2011/06/memory-footprints-of-some-common-data.html


11
Я не думаю, що ASCII має до цього щось спільне: і String, і Text однаково підтримують Unicode, висуваючи фактичне кодування під ваш рівень абстракції. В обох випадках вам доведеться турбуватися про це лише на межі вашої програми. Підтримка Unicode не є хорошим критерієм для вибору між ними.
Тихон Джелвіс,

4
Ви переплутали Stringз ByteStringвідносно ASCII.
Микита Волков

1
@TikhonJelvis чи не існує проблема в тому, що один Charіз рядків може бути лише частиною символу Unicode, а не жодного символу Unicode? Це не спричинить сум'яття? Чи вирішує це Data.Text?
João Portela

3
@ João Portela: Haskell Charне схожі на Java чи C # char. Вони є повними кодовими точками Unicode (32 біти).
Тобіас Брандт

1
Вони 32-бітні? Я завжди вважав, що вони 16-бітові. Дякуємо за роз'яснення.
João Portela

9

Є як мінімум три причини використовувати [Char] у невеликих проектах.

  1. [Char] не покладається на будь-який таємний персонал, такий як іноземні вказівники, необроблена пам’ять, необроблені масиви тощо, які можуть працювати по-різному на різних платформах або навіть взагалі бути недоступними

  2. [Char]- це лінгва-франка в Haskell. Є принаймні три «ефективні» способів впоратися з Юникоде даних в Haskell: utf8-bytestring, Data.Text.Textі Data.Vector.Unboxed.Vector Char, кожен з яких вимагає роботи з додатковим пакетом.

  3. за допомогою [Char]одного отримує доступ до всієї потужності []монади, включаючи багато специфічних функцій (альтернативні рядкові пакети намагаються допомогти з цим, але все ж)

Особисто я вважаю основою utf16 Data.Textодне з найбільш сумнівних висновків спільноти haskell, оскільки utf16 поєднує в собі недоліки як кодування utf8, так і utf32 , не маючи жодної з їх переваг.


1
Чи можете ви дати більше інформації про те, чому ви вважаєте utf16 нижчим? Не обов’язково як частина цієї відповіді, але, можливо, до статті, де детально описується ваша позиція.
Wizek

2
@Wizek - це досить поширена думка. Див. Programmers.stackexchange.com/questions/102205/… .
Жуль,

5

Цікаво, чи Data.Text завжди ефективніший за Data.String ???

"мінусами", наприклад, є O (1) для рядків і O (n) для тексту. Додаток - O (n) для рядків та O (n + m) для строгих текстів. Так само,

    let foo = "foo" ++ bigchunk
        bar = "bar" ++ bigchunk

є більш просторим для струн, ніж для строгих текстів.

Інша проблема, не пов’язана з ефективністю, - це збіг з шаблоном (чіткий код) та ледачість (передбачувано для кожного символу в рядках, певна залежність від реалізації в ледачому тексті).

Тексти, очевидно, гарні для статичних послідовностей символів та для модифікації на місці. Для інших форм структурного редагування Data.String може мати переваги.


1
У продуктивності та ефективності є не тільки великі о. Реалізація рядка - це зв’язаний список із вузлом для кожного окремого символу. Це багато додаткової пам’яті, кеш-пам’яті та фрагментації для простого рядка.
Джастін Майнерс,

4

Я не думаю, що існує одна технічна причина, щоб String залишався. І я бачу кілька таких, щоб це пішло.

Загалом, я спершу стверджую, що у випадку Text / String є лише одне найкраще рішення:

  • Струнні виступи погані, у цьому всі погоджуються

  • Текст не складний у використанні. Усі функції, які зазвичай використовуються в рядку, доступні в тексті, а також деякі корисні функції в контексті рядків (заміна, доповнення, кодування)

  • наявність двох рішень створює непотрібну складність, якщо всі базові функції не зроблені поліморфними. Доказ: є SO запитання на тему автоматичних перетворень . Таким чином , це є проблемою.

Отже, одне рішення менш складне, ніж два, і недоліки String змусять його з часом зникнути. Швидше, тим краще !


1
Це не так просто, ні. Існує чимала кількість нетривіального коду обробки рядків, який розроблений навколо Stringі який взагалі не буде добре працювати Text.
dfeuer

@dfeuer Мені б дуже цікаві вказівки - мені дуже бракує досвіду з перших рук у цих справах.
Titou
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.