Создание вариантов кортежей из списка - Haskell
Я относительный новичок в Haskell и пытаюсь создать список кортежей с уравнением, которое я назвал splits
который изначально возникает из одного списка, например:
splits [1..4] --> [ ([1],[2,3,4]), ([1,2],[3,4]), ([1,2,3],[4]) ]
или же
splits "xyz" --> [ ("x","yz"), ("xy","z") ]
Создание списка кортежей, которые принимают 1, затем 2, затем 3 элемента и т. Д. Я понял, что, вероятно, я должен использовать функции take/drop, но это то, что у меня есть, и я сталкиваюсь с большим количеством объявлений типов ошибки... есть идеи?
splits :: (Num a) => [a] -> [([a], [a])]
splits [] = error "shortList"
splits [x]
| length [x] <= 1 = error "shortList"
| otherwise = splits' [x] 1
where splits' [x] n = [(take n [x], drop n [x])] + splits' [x] (n+1)
4 ответа
Подход Haskell-y заключается в использовании inits
а также tails
функции от Data.List
:
inits [1,2,3,4] = [ [], [1], [1,2], [1,2,3], [1,2,3,4] ]
tails [1,2,3,4] = [ [1,2,3,4], [2,3,4], [3,4], [4], [] ]
Затем мы просто объединяем эти два списка и удаляем первую пару:
splits xs = tail $ zip (inits xs) (tails xs)
или, что то же самое, сначала удалите первый элемент каждого из списков компонентов:
= zip (tail (inits xs)) (tail (tails xs))
splits [] = []
splits [_] = []
splits (x:xs) = ([x], xs) : map (\(ys, zs) -> (x:ys, zs)) (splits xs)
У вас есть несколько ошибок.
Вам не нужно иметь Num a
класс для a
,
использование []
или же [x]
в качестве шаблона, но не переменной, используйте xs
вместо.
использование ++
вместо +
для объединения списков.
В нашем случае используйте (:)
добавить список к значению вместо ++
,
Добавьте стоп для рекурсии, как дополнительную переменную maxn
в splits'
splits :: [a] -> [([a], [a])]
splits [] = error "shortList"
splits xs
| lxs <= 1 = error "shortList"
| otherwise = splits' xs 1 lxs
where
lxs = length xs
splits' xs n maxn
| n > maxn = []
| otherwise = (take n xs, drop n xs) : splits' xs (n+1) maxn
Существует встроенная функция, которая делает часть того, что вы хотите:
splitAt :: Int -> [a] -> ([a], [a])
который делает то, на что он похож
> splitAt 2 [1..4]
([1,2],[3,4])
Используя эту функцию, вы можете просто определить разбиения следующим образом:
splits xs = map (flip splitAt xs) [1..length xs - 1]