リスト (または文字列) を取り、それを N 個の要素のサブリストに分割したいと考えています。Haskell でどのように行うのですか?
例:
mysteryFunction 2 "abcdefgh"
["ab", "cd", "ef", "gh"]
リスト (または文字列) を取り、それを N 個の要素のサブリストに分割したいと考えています。Haskell でどのように行うのですか?
例:
mysteryFunction 2 "abcdefgh"
["ab", "cd", "ef", "gh"]
cabal update
cabal install split
そして、から使用chunksOf
しますData.List.Split
import Data.List
import Data.Function
mysteryFunction n = map (map snd) . groupBy ((==) `on` fst) . zip ([0..] >>= replicate n)
... 冗談だ...
すでにあります
Prelude Data.List> :t either
either :: (a -> c) -> (b -> c) -> Either a b -> c
と
Prelude Data.List> :t maybe
maybe :: b -> (a -> b) -> Maybe a -> b
だから本当にあるはずです
list :: t -> ([a] -> t) -> [a] -> t
list n _ [] = n
list _ c xs = c xs
同じように。それと、
import Data.List (unfoldr)
g n = unfoldr $ list Nothing (Just . splitAt n)
それなしで、
g n = takeWhile (not.null) . unfoldr (Just . splitAt n)
mysteryFunction x "" = []
mysteryFunction x s = take x s : mysteryFunction x (drop x s)
おそらく、あなたが考えていたエレガントなソリューションではありません。
ファンシーな答え。
上記の回答では、再帰的な splitAt も使用する必要があります。再帰的なソリューションをゼロから構築する方法を見てみましょう。
Functor L(X)=1+A*X は、X を 1 にマップするか、A と X のペアに分割することができ、最小固定点として List(A) を持ちます。List(A) は 1+ にマップできます。 A*List(A) と同型を使用して戻る; つまり、空でないリストを分解する方法は 1 つしかなく、空のリストを表す方法は 1 つしかありません。
Functor F(X)=List(A)+A*X は似ていますが、リストの末尾は空のリスト ("1") ではなくなり、ファンクターは値 A を抽出したり、X をリストに変換したりできます。 Asの。その場合、List(A) はその不動点 (ただし、最小固定点ではなくなります) であり、ファンクターは任意のリストをリストとして、または要素とリストのペアとして表すことができます。事実上、任意のコールジェブラは、リストの分解を「自由に」「停止」できます。
{-# LANGUAGE DeriveFunctor #-}
import Data.Functor.Foldable
data N a x = Z [a] | S a x deriving (Functor)
(これは、次の簡単なインスタンスを追加するのと同じです):
instance Functor (N a) where
fmap f (Z xs) = Z xs
fmap f (S x y) = S x $ f y
ハイロモルフィズムの定義を考えてみましょう:
hylo :: (f b -> b) -> (c -> f c) -> c -> b
hylo psi phi = psi . fmap (hylo psi phi) . phi
シード値を指定すると、phi を使用して fc を生成し、fmap は hylo psi phi を再帰的に適用し、psi は fmap された構造体 f b から b を抽出します。
このファンクターの (コ) 代数のペアのハイロモーフィズムは、splitAt です。
splitAt :: Int -> [a] -> ([a],[a])
splitAt n xs = hylo psi phi (n, xs) where
phi (n, []) = Z []
phi (0, xs) = Z xs
phi (n, (x:xs)) = S x (n-1, xs)
このコールジェブラは、抽出する頭部があり、抽出された要素のカウンターがゼロでない限り、頭部を抽出します。これは、ファンクターがどのように定義されたかによるものです。phi が S xy を生成する限り、hylo は y を次のシードとして phi に供給します。Z xs が生成されると、ファンクターは hylo psi phi をそれに適用しなくなり、再帰は停止します。
同時に、hylo は構造をリストのペアに再マッピングします。
psi (Z ys) = ([], ys)
psi (S h (t, b)) = (h:t, b)
これで、splitAt がどのように機能するかがわかりました。アポモーフィズムを使用して、それを splitList に拡張できます。
splitList :: Int -> [a] -> [[a]]
splitList n xs = apo (hylo psi phi) (n, xs) where
phi (n, []) = Z []
phi (0, xs) = Z xs
phi (n, (x:xs)) = S x (n-1, xs)
psi (Z []) = Cons [] $ Left []
psi (Z ys) = Cons [] $ Right (n, ys)
psi (S h (Cons t b)) = Cons (h:t) b
今回は、再マッピングはアポモルフィズムで使用するように適合されています。右である限り、アポモルフィズムは hylo psi phi を使用してリストの次の要素を生成し続けます。Left の場合は、リストの残りを 1 ステップで生成します (この場合は、[] でリストを終了するだけです)。