Я пытаюсь сделать приведенный ниже код Haskell равным коду Python, но он не работает, и я не могу обнаружить ошибку? Может ли кто-нибудь заметить ошибку? Вывод Python - это то, что я хочу
def balanceList(lst):
length = len(lst)
if length<3:
return lst
else:
middle=length//2
return [lst[middle]] + balance(lst[middle+1:] + balance(lst[:middle]))
print( balanceList(list(range(1,10))) )
# [5, 3, 8, 2, 7, 4, 9, 6, 1]
balanceList :: [a] -> [a]
balanceList lst
| len < 3 = lst
| otherwise = [lst !! middle] ++ balanceList (drop (middle+1) lst) ++ balanceList (take (middle) lst)
where len = length lst; middle = len `div` 2
-- >>> balanceList [1..9]
-- [5,8,9,6,7,3,4,1,2]
Не беспокойтесь о смысле. Но да, скобки, где проблема...
Это проблема со скобками:
balanceList :: [a] -> [a]
balanceList lst
| len < 3 = lst
| otherwise = [lst !! middle] ++ balanceList (drop (middle+1) lst ++ balanceList (take (middle) lst))
where len = length lst
middle = len `div` 2
Здесь мы таким образом уравновешиваем первую часть, добавляем последнюю часть и снова уравновешиваем. Но неясно, было ли это намерением в Python.
Но использование length
не очень похоже на Haskell. Вы можете разделить список на три с помощью рекурсии:
splitMiddle :: [a] -> ([a], a, [a])
splitMiddle ls = go ls ls
where go [] (x:xs) = ([], x, xs)
go [_] ~(x:xs) = ([], x, xs)
go (_:_:ys) ~(x:xs) = let ~(b, m, a) = go ys xs in (x:b, m, a)
или с NonEmpty
:
import Data.List.NonEmpty(NonEmpty((:|)))
splitMiddle :: NonEmpty a -> ([a], a, [a])
splitMiddle (x :| xs) = go (x:xs) x xs
where go [] x xs = ([], x, xs)
go [_] x xs = ([], x, xs)
go (_:_:ys) x ~(x1:xs) = let ~(b, m, a) = go ys x1 xs in (x:b, m, a)
Затем мы можем использовать это для разделения и слияния:
balanceList :: [a] -> [a]
balanceList lst@(_:_:_:_) = m : balanceList (a ++ balanceList b)
where (b, m, a) = splitMiddle lst
balanceList lst = lst
Не уверен, что предпочитаю splitMiddle
length
+splitAt
, тем более, что он не тотальный.
Да скобки! Как плохо я этого не видел :(
@leftaroundabout: Я думаю, что lst!!middle
является проблемной частью. splitMiddle
, вероятно, должен работать с NonEmpty
.
Ага, но тогда еще и в NonEmpty
нужно конвертировать в balanceList
, это довольно неудобно. Я бы использовал balanceList lst = case splitAt (length lst`div`2) lst of {(l,m:r) -> ...}
Вы уверены, что версия Python верна? Вы пишете
balance(lst[middle+1:] + balance(lst[:middle]))
, ноbalance(lst[middle+1:]) + balance(lst[:middle])
кажется более естественным желанием.