Первая попытка на Haskell: преобразование строчных букв в прописные

Я недавно начал изучать Haskell, и я попытался создать функцию для преобразования слова в нижнем регистре в слово в верхнем регистре, это работает, но я не знаю, насколько это хорошо, и у меня есть несколько вопросов. Код:

lowerToUpperImpl element list litereMari litereMici = 
 do
  if not (null  list) then
   if (head list) == element then
     ['A'..'Z'] !! (length ['A'..'Z'] - length (tail list ) -1)
   else
     lowerToUpperImpl element (tail list) litereMari litereMici
  else
    '0' --never to be reached

lowerToUpper element = lowerToUpperImpl element ['a'..'z'] ['A'..'Z'] ['a'..'z']

lowerToUpperWordImpl word  = 
 do 
  if not (null word) then
   lowerToUpper (head (word)):(lowerToUpperWordImpl (tail word))
  else
   ""
  1. Мне не нравится, как я передал буквы в верхнем и нижнем регистре, я не могу просто объявить глобальные переменные или что-то еще?
  2. Как бы вы подошли к заполнению мертвой ветки?

Каковы будут ваши предложения по улучшению этого?

2 ответа

Решение

Во-первых, если /else обычно рассматривается как опора в функциональных языках программирования, именно потому, что они на самом деле не должны использоваться как операции ветвления, а как функции. Также помните, что списки не знают своей длины в Haskell, поэтому вычисление O(n) шаг. Это особенно плохо для бесконечных списков.

Я бы написал так: (если бы я не импортировал библиотеки):

uppercase :: String -> String
uppercase = map (\c -> if c >= 'a' && c <= 'z' then toEnum (fromEnum c - 32) else c)

Позволь мне объяснить. Этот код использует Enum а также Ord Типы классов, которые Char удовлетворяет. fromEnum c переводит c к его ASCII-коду и toEnum принимает коды ASCII к их эквивалентным символам. Функция, которую я поставляю map просто проверяет, что символ в нижнем регистре и вычитает 32 (разница между "A" и "a"), если он есть, и оставляет его в покое в противном случае.

Конечно, вы всегда можете написать:

import Data.Char
uppercase :: String -> String
uppercase = map toUpper

Надеюсь это поможет!

Вот что я всегда рекомендую людям в ваших обстоятельствах:

  1. Разбейте проблему на более мелкие части и напишите отдельные функции для каждой части.
  2. Используйте библиотечные функции везде, где вы можете решить мелкие подзадачи.
  3. В качестве упражнения после того, как вы закончите, выясните, как самостоятельно написать используемые вами библиотечные функции.

В этом случае мы можем применить пункты следующим образом. Во-первых, так как String в Хаскеле это синоним [Char] (список Char), мы можем разбить вашу проблему на две части:

  • Превратите персонажа в заглавную копию.
  • Преобразуйте список, применяя функцию отдельно для каждого из его членов.

Второй момент: как указывает ответ Алекса, Data.Char стандартный модуль библиотеки поставляется с функцией toUpper который выполняет первую задачу, а Prelude библиотека поставляется с map который выполняет второй. Таким образом, использование этих двух вместе решает вашу проблему немедленно (и это именно тот код, который Алекс написал ранее):

import Data.Char
uppercase :: String -> String
uppercase = map toUpper

Но я бы сказал, что это лучшее решение (самое короткое и ясное), и для новичка это первый ответ, который вы должны попробовать.

Применяя мой третий пункт: после того, как вы придумали стандартное решение, очень полезно попытаться написать свои собственные версии функций библиотеки, которые вы использовали. Дело в том, что таким образом вы изучаете три вещи:

  1. Как разбить проблемы на более легкие, более мелкие части, желательно многоразовые;
  2. Содержание стандартных библиотек языка;
  3. Как написать простые "фундаментальные" функции, которые предоставляет библиотека.

Таким образом, в этом случае вы можете попробовать написать свои собственные версии toUpper а также map, Я предоставлю скелет для map:

map :: (a -> b) -> [a] -> [b]
map f [] = ???
map f (x:xs) = ???
Другие вопросы по тегам