Функция, которую вы написали, не может быть уменьшена только с помощью Prelude
, потому что нет способа уменьшить оператор if
. (Эрих указывает, что это можно сделать с помощью bool
из Data.Bool
.) Здесь я придумываю альтернативное лечение, которое можно уменьшить, но я надеюсь, что к концу я убедил вас не делать этого.
Функция, которую вы можете найти здесь полезной: break
. Из Hackage :
, примененного к предикату p и списку xs, возвращает кортеж, где первый элемент - самый длинный префикс (возможно, пустой) из xs элементов, которые не удовлетворяют p и второй элемент является остатком списка
Таким образом, мы можем построить функцию для разделения вашего списка на определенный элемент:
splitOnChar :: Char -> String -> (String, String)
splitOnChar char = break (char ==)
Оттуда мы можем разработать функцию сделать так, как вы описываете:
replaceChar :: Char -> String -> String -> String
replaceChar char repstr instr =
case break (char ==) instr of
(front, _:back) -> front ++ repstr ++ back
_ -> error "Character to replace not found!"
Это позволяет вам избавиться от оператора if
, который невозможно написать бессмысленно. С какой стати вы захотите написать эту точку бесплатно, это мне не по карману, но для этого нам нужно пожертвовать обработкой ошибок. Давайте посмотрим на версию, которая отбрасывает обработку
replaceChar :: Char -> String -> String -> String
replaceChar char repstr instr =
let ~(front, _:back) = break (char ==) instr
in front ++ repstr ++ back
Тогда мы можем заменить front
и back
на выражения:
replaceChar :: Char -> String -> String -> String
replaceChar char repstr instr =
let split = break (char ==) instr
in (fst split) ++ repstr ++ (tail $ snd split)
Теперь давайте переместим split
в конец оператора in
:
replaceChar :: Char -> String -> String -> String
replaceChar char repstr instr =
let split = break (char ==) instr
in (\a b -> a ++ repstr ++ b) <$> fst <*> tail . snd $ split
Теперь мы можем подставить split
:
replaceChar :: Char -> String -> String -> String
replaceChar char repstr instr =
(\a b -> a ++ repstr ++ b) <$> fst <*> tail . snd $ break (char ==) instr
Далее давайте сделаем eta-Reduce b
из нашего лямбда-выражения:
replaceChar :: Char -> String -> String -> String
replaceChar char repstr instr =
(\a -> ((a ++ repstr) ++)) <$> fst <*> tail . snd $ break (char ==) instr
Затем сделайте то же самое с a
:
replaceChar :: Char -> String -> String -> String
replaceChar char repstr instr =
((. (repstr ++)) . (++)) <$> fst <*> tail . snd $ break (char ==) instr
Затем замените instr
:
replaceChar :: Char -> String -> String -> String
replaceChar char repstr =
(((. (repstr ++)) . (++)) <$> fst <*> tail . snd) . break (char ==)
Теперь проще уменьшить char
, поэтому мы Я просто переверну аргументы и вспомню flip
их позже.
replaceChar :: String -> Char -> String -> String
replaceChar repstr char =
(((. (repstr ++)) . (++)) <$> fst <*> tail . snd) . break (char ==)
А теперь мы действительно уменьшим char
:
replaceChar :: String -> Char -> String -> String
replaceChar repstr =
((((. (repstr ++)) . (++)) <$> fst <*> tail . snd) .) . break . (==)
Теперь нам нужно переставить вся функция, чтобы получить repstr
в конце. Начните с превращения . break . (==)
в раздел:
replaceChar :: String -> Char -> String -> String
replaceChar repstr =
(. break . (==)) $ ((((. (repstr ++)) . (++)) <$> fst <*> tail . snd) .)
Разрезание второй половины:
replaceChar :: String -> Char -> String -> String
replaceChar repstr =
(. break . (==)) $ (.) $ ((. (repstr ++)) . (++)) <$> fst <*> tail . snd
Раздел <*> tail . snd
replaceChar :: String -> Char -> String -> String
replaceChar repstr =
(. break . (==)) $ (.) $ (<*> tail . snd) $ ((. (repstr ++)) . (++)) <$> fst
Раздел <$> fst
:
replaceChar :: String -> Char -> String -> String
replaceChar repstr =
(. break . (==)) $ (.) $ (<*> tail . snd) $ (<$> fst) $ (. (repstr ++)) . (++)
Раздел . (++)
:
replaceChar :: String -> Char -> String -> String
replaceChar repstr =
(. break . (==)) $ (.) $ (<*> tail . snd) $ (<$> fst) $ (. (++)) $ (. (repstr ++))
Unsection (. (repstr ++))
:
replaceChar :: String -> Char -> String -> String
replaceChar repstr =
(. break . (==)) $ (.) $ (<*> tail . snd) $ (<$> fst) $ (. (++)) $ flip (.) $ (repstr ++)
Unsection (repstr ++)
:
replaceChar :: String -> Char -> String -> String
replaceChar repstr =
(. break . (==)) $ (.) $ (<*> tail . snd) $ (<$> fst) $ (. (++)) $ flip (.) $ (++) repstr
Eta-Reduce:
replaceChar :: String -> Char -> String -> String
replaceChar =
(. break . (==)) . (.) . (<*> tail . snd) . (<$> fst) . (. (++)) . flip (.) . (++)
И flip
, чтобы вернуть аргументы в правильном порядке:
replaceChar :: Char -> String -> String -> String
replaceChar =
flip $ (. break . (==)) . (.) . (<*> tail . snd) . (<$> fst) . (. (++)) . flip (.) . (++)
Et-voilà: совершенно неразборчивая куча гиббери sh волшебным образом делает то, что вам нужно, без какой-либо причины, понятной человечеству.