Haskell , 74 67 63 байта
r=read
f x|(a,(c,s:d):_)<-lex<$>lex x!!0=show(r a*r d+r c)++s:d
Попробуйте онлайн!
объяснение
Как выяснил H.PWiz , мы можем использовать лексер Haskell, чтобы разбить строку на части. (Ранее я использовал span(>'/')
) И Лайкони указал, что <$>
работает так же, как и mapSnd
из Data.Tuple
.
Паттерн-охранник разбивает наш код на три числа, которые мы хотим использовать lex
. lex
вызывает лексера haskell, чтобы разорвать первый токен. Возвращает список с каждым элементом, представляющим возможный способ разбора строки. Эти элементы являются кортежами, причем первый элемент является первым токеном, а остальная часть строки - вторым элементом. Теперь, поскольку формат ввода очень регулярный, у нас будет только один разбор, поэтому мы всегда можем взять первый. Первое, что мы делаем, это вызываем lex
на входе
lex x
Затем мы разворачиваем его из списка, давая нам 2-кортеж
lex x!!0
Первым маркером будет вся часть смешанной фракции, оставляющая фракцию с добавленным пробелом для анализа. Тогда, поскольку кортежи есть, Functors
мы можем использовать (<$>)
псевдоним для fmap
применения lex
ко второму элементу кортежа.
lex<$>lex x!!0
Это проглатывает пространство и обрывает следующий токен, числитель нашей дроби. Теперь мы привязываем это к сопоставлению с образцом, используя <-
. Наш образец
(a,(c,s:d):_)
a
захватывает всю часть дроби, наш первый жетон. :_
разворачивает список, полученный в результате нашего второго lex
. c
берет второй лексем, который мы лексировали, это числитель дроби. Все, что остается, связано с тем, s:d
что разделяет его на первый символ, гарантированный форматом/
а остальная часть будет знаменателем.
Теперь, когда мы проанализировали вход, мы делаем фактические вычисления:
show(r a*r d+r c)++s:d
Где r
функция чтения, которую мы связали ранее.
Важно отметить, что lex
возвращает список пустым, если он терпит неудачу, и непустым, если он успешен. Почему это не Maybe
я не знаю.