Als Typ-hackery Übung ist es möglich, dies mit Standardlisten zu implementieren.
Alles, was wir brauchen, ist eine beliebige Tiefe groupStringsBy Funktion:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts,
UndecidableInstances, IncoherentInstances,
TypeFamilies, ScopedTypeVariables #-}
import Data.List
import Data.Function
class StringGroupable a b where
groupStringBy :: Pred -> a -> b
instance (StringGroupable a b, r ~ [b]) => StringGroupable [a] r where
groupStringBy f = map (groupStringBy f)
instance (r ~ [[String]]) => StringGroupable [String] r where
groupStringBy p = groupBy p
die wie folgt funktioniert:
*Main> let lst = ["11","11","22","1","2"]
*Main> groupStringBy ((==) `on` length) lst
[["11","11","22"],["1","2"]]
*Main> groupStringBy (==) . groupStringBy ((==) `on` length) $ lst
[[["11","11"],["22"]],[["1"],["2"]]]
So können wir diese Funktion direkt verwenden (obwohl es in umgekehrter Reihenfolge gestellt werden muss,):
inp = ["1.1", "1.2.1", "1.2.2", "2.1", "2.2", "3"]
deweyGroup :: Int -> String -> String -> Bool
deweyGroup i a b = a!!idx == b!!idx where idx = 2*(i-1)
-- gives: [[["1.1"],["1.2.1","1.2.2"]],[["2.1"],["2.2"]],[["3"]]]
test1 = groupStringBy (deweyGroup 2) . groupStringBy (deweyGroup 1) $ inp
Aber wenn Sie Ihre ursprüngliche Probe verwenden möchten, können wir es auch hacken. Zuerst brauchen wir eine variable Argument Funktion, die Pipelines alle Argumente, aber die letzte in umgekehrter Reihenfolge über .
und dann die resultierende Funktion auf das letzte Argument gilt:
class App a b c r where
app :: (a -> b) -> c -> r
instance (b ~ c, App a d n r1, r ~ (n -> r1)) => App a b (c -> d) r where
app c f = \n -> app (f . c) n
instance (a ~ c, r ~ b) => App a b c r where
app c a = c a
funktioniert wie folgt:
*Main> app not not not True
False
*Main> app (+3) (*2) 2
10
Dann erweitern sie es für unser Prädikat-Typ mit einer benutzerdefinierten Regel type Pred = String -> String -> Bool
:
type Pred = String -> String -> Bool
instance (StringGroupable b c, App a c n r1, r ~ (n -> r1)) => App a b Pred r where
app c p = app ((groupStringBy p :: b -> c) . c)
Und schließlich w rap es in rGroupBy
(Versorgung id
Funktion die erste in der Pipeline sein):
rGroupBy :: (App [String] [String] Pred r) => Pred -> r
rGroupBy p = app (id :: [String] -> [String]) p
Nun Pred
Herstellung der Liste der Tiefe, die gleich der Anzahl der gelieferten Prädikate der Gruppierungs Prädikate der Art für eine beliebige Anzahl arbeiten sollte :
-- gives: [["1.1","1.2.1","1.2.2"],["2.1","2.2"],["3"]]
test2 = rGroupBy (deweyGroup 1) inp
-- gives: [[["1.1"],["1.2.1","1.2.2"]],[["2.1"],["2.2"]],[["3"]]]
test3 = rGroupBy (deweyGroup 1) (deweyGroup 2) inp
-- gives: [[[["1.1"]],[["1.2.1","1.2.2"]]],[[["2.1"]],[["2.2"]]],[[["3"]]]]
test4 = rGroupBy (deweyGroup 1) (deweyGroup 2) (deweyGroup 1) inp
so ist es möglich (und wahrscheinlich auch vereinfacht werden kann), aber wie immer mit dieser Art von Hacks wird nicht empfohlen, aber die Übung für alles verwendet werden.
interessante Frage. Wenn du sagst "es ist nicht im Voraus bekannt" meinst du zur Kompilierzeit? Wenn dem so ist, dann haben Sie vielleicht kein Glück, denn Hakkell ist statisch getippt. – jberryman
in C/C++ eine Liste ist normalerweise ein Array, ein Array ist in der Regel eine 2-dimensionale Matrix, eine Liste von Arrays bedeutet, dass Sie die Dimensionen um 1 erhöhen, von 2 bis 3, eine Liste von Array ist eine 3D-Matrix (aus einem abstrakten Blickwinkel); Ich weiß nicht, Haskell, aber wahrscheinlich ist Ihr Problem nur über Matrix/Vektor-Dimensionen. – user827992
@ user827992, in Haskell ist eine Liste eine Liste, kein Array.(Es ist eine einfach verknüpfte Liste, um genau zu sein) – dflemstr