Другие ответы показывают, как сделать это идиоматически с нуля, что мне очень нравится.Также может быть интересно показать, как вы можете отполировать то, что у вас уже есть.Здесь снова напоминание:
concatsplit a = concatMap (\(x,y)-> concatsplit' (x,y)) a
concatsplit' y = map (\x -> ((fst y),x)) (snd y)
Первое, что я бы последовательно изменил, называется «сокращение этажа», и это когда вы превращаете что-то из формы \x -> foo x
в просто foo
,Мы можем сделать это в аргументе concatMap
, чтобы получить
concatsplit a = concatMap concatsplit' a
, а затем снова в аргументе concatsplit
, чтобы получить:
concatsplit = concatMap concatsplit'
Глядя на concatsplit'
,меньше всего мне нравится использование fst
и snd
вместо сопоставления с образцом.При сопоставлении с образцом это выглядит так:
concatsplit' (a,bs) = map (\x -> (a,x)) bs
Если вы действительно хотите попрактиковаться в сокращении eta, вы можете заметить, что (,)
можно применить к префиксу, и измените его на
concatsplit' (a,bs) = map (\x -> (,) a x) bs
= map ((,) a) bs
но я думаю, что я так же счастлив, так или иначе.На данный момент, это определение достаточно мало, чтобы я соблазнился вставить его в concatsplit
сам, получив:
concatsplit = concatMap (\(a,bs) -> map ((,) a) bs)
Это выглядит как довольно хорошее определение для меня, и я бы остановилсятам.
Вы могут быть прослушены почти-eta-сокращением здесь: это почти правильная форма для отбрасывания bs
.Опытный пользователь мог бы продолжить, заметив, что:
uncurry (\a bs -> map ((,) a) bs) = \(a,bs) -> map ((,) a) bs
Следовательно, с помощью некоторого сокращения этажа и других бессмысленных техник мы могли бы перейти следующим образом:
concatsplit = concatMap (uncurry (\a bs -> map ((,) a) bs))
= concatMap (uncurry (\a -> map ((,) a)))
= concatMap (uncurry (map . (,)))
Но, лично,Я нахожу это менее читабельным, чем там, где я объявил, что остановлюсь выше, а именно:
concatsplit = concatMap (\(a,bs) -> map ((,) a) bs)