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я не знаю.