Como un ejercicio de tipo hackery es posible implementar esto con listas estándar.
Todo lo que necesitamos es una función de la profundidad groupStringsBy arbitraria:
{-# 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
que funciona como esto:
*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"]]]
así que podemos usar esta función directamente (aunque tiene que ser puesto en orden inverso):
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
Pero si quiere usar su muestra original, podemos hackearla también. Primero necesitamos una función de la variable argumento que las tuberías de todos los argumentos pero el último en el orden inverso a través de .
y luego se aplica la función resultante para el último argumento:
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
funciona así:
*Main> app not not not True
False
*Main> app (+3) (*2) 2
10
a continuación, expanda con una regla personalizada para nuestro tipo de predicados 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)
Y finalmente w rap en rGroupBy
(suministro de id
función sea la primera en la tubería):
rGroupBy :: (App [String] [String] Pred r) => Pred -> r
rGroupBy p = app (id :: [String] -> [String]) p
Ahora debería funcionar para cualquier número de agrupar predicados de tipo Pred
que producen la lista de la profundidad igual al número de predicados suministrados :
-- 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
lo que es posible (y, probablemente, se puede simplificar) pero como siempre con este tipo de hackery no está recomendado para ser utilizado para otra cosa que el ejercicio.
pregunta interesante. Cuando dices "no se sabe desde el principio", ¿te refieres al momento de la compilación? Si es así, puede que no tenga suerte, ya que haskell está tipado estáticamente. – jberryman
en C/C++ una lista es generalmente una matriz, una matriz es generalmente una matriz de 2 dimensiones, hacer una lista de matrices significa que está aumentando las dimensiones en 1, de 2 a 3, una lista de matriz es una matriz 3D (desde un punto de vista abstracto); No conozco a Haskell, pero probablemente su problema sea sobre las dimensiones de matriz/vector. – user827992
@ user827992, en Haskell, una lista es una lista, no una matriz.(Es una lista unida individualmente, para ser precisos) – dflemstr