Saturday 30 April 2016

Haskell: XTransformListComp : Enhance List extensions


By enabling XTransformListComp extension, we can further enhance list comprehensions and perform operations such as sorting and grouping which are familiar from SQL.

How to enable XTransformListComp?
:set –XTransformListComp

Run above command in GHCi to enable XTransformListComp.

After enabling the GHCi extension, you can use the keyword then to enhance list comprehensions. Following are the different forms of then keyword.
         1. then f
         2. then f by e
         3. then group by e using f
         4. then group using f

then f        
This statement requires that f have the type forall a. [a] -> [a]
Prelude> :set -XTransformListComp
Prelude> [x^2 | x <- [1, 5, -3, 4, 8, -10], then reverse]
[100,64,16,9,25,1]


Examples
1. Square every element of list and then reverse
ListUtil.hs
{-# LANGUAGE TransformListComp #-}
squareReverse :: [Integer] -> [Integer]
squareReverse list = [x^2 | x <- list, then reverse]

Prelude> :load ListUtil.hs
[1 of 1] Compiling Main             ( ListUtil.hs, interpreted )
Ok, modules loaded: Main.
*Main> 
*Main> squareReverse [1, -2, 8, -6]
[36,64,4,1]
 
then f by e
This is similar to then statement, but allows you to create a function which will be passed as the first argument to f.. This statement requires that f have the type (a -> t) -> [a] -> [a].
1. Square every element of list and then sort
ListUtil.hs

{-# LANGUAGE TransformListComp #-}

import GHC.Exts

squareSort :: [Integer] -> [Integer]
squareSort list = [x^2 | x <- list, then sortWith by x^2]

Prelude> :load ListUtil.hs
[1 of 1] Compiling Main             ( ListUtil.hs, interpreted )
Ok, modules loaded: Main.
*Main> 
*Main> squareSort [1, -2, 10, -8, 3, 5]
[1,4,9,25,64,100]


2.  Sort elements of list of string by their length.
ListUtil.hs
{-# LANGUAGE TransformListComp #-}

import GHC.Exts

sortList :: [String] -> [String]
sortList list = [x | x <- list, then sortWith by (length x)]

Prelude> :load ListUtil.hs
[1 of 1] Compiling Main             ( ListUtil.hs, interpreted )
Ok, modules loaded: Main.
*Main> 
*Main> sortList ["Hari", "Krishna", "PTR", "Nayan"]
["PTR","Hari","Nayan","Krishna"]
*Main> 


then group by e using f
By using above statement we can perform grouping operations. In this form, f is required to have type forall a. (a -> t) -> [a] -> [[a]].

1. Group list of names using their length
ListUtil.hs
{-# LANGUAGE TransformListComp #-}

import GHC.Exts

processInfo list = [ (the len, name) | name <- list, let len = length name, then group by len using groupWith ]

Prelude> :load ListUtil.hs
[1 of 1] Compiling Main             ( ListUtil.hs, interpreted )
Ok, modules loaded: Main.
*Main> 
*Main> processInfo ["Hari", "Krishna", "PTR", "Nayan", "Rama", "Gopi", "Sudheer"]
[(3,["PTR"]),(4,["Hari","Rama","Gopi"]),(5,["Nayan"]),(7,["Krishna","Sudheer"])]
*Main> 


Rerun List Util.hs by removing the keyword ‘the’, you will get following output.
*Main> processInfo ["Hari", "Krishna", "PTR", "Nayan", "Rama", "Gopi", "Sudheer"]
[([3],["PTR"]),([4,4,4],["Hari","Rama","Gopi"]),([5],["Nayan"]),([7,7],["Krishna","Sudheer"])]


‘the’ function to change the type of length of names from a list to its original numeric type.
*Main> :t the
the :: Eq a => [a] -> a
*Main> 
*Main> the [1, 1, 1]
1
*Main> the ["abc", "abc", "abc"]
"abc"


2. Given a list of tuples like this:

dic = [(1,"aa"),(1,"cc"),(2,"aa"),(3,"ff"),(3,"gg"),(1,"bb")]

Group hem by using first element of every tuple.

ListUtil.hs
{-# LANGUAGE TransformListComp #-}

import GHC.Exts
import Data.List
import Data.Function (on)

process :: [(Integer, String)] -> [(Integer, [String])]
process list = [ (the x, y) | (x, y) <- list, then  group by x using groupWith ]

Prelude> :load ListUtil.hs
[1 of 1] Compiling Main             ( ListUtil.hs, interpreted )
Ok, modules loaded: Main.
*Main> 
*Main> process [(1,"aa"),(1,"cc"),(2,"aa"),(3,"ff"),(3,"gg"),(1,"bb")]
[(1,["aa","cc","bb"]),(2,["aa"]),(3,["ff","gg"])]


3. Given a list of tuples like this:

dic = [(1,"aa"),(1,"cc"),(2,"aa"),(3,"ff"),(3,"gg"),(1,"bb")]

Group hem by using second element of every tuple.

ListUtil.hs
{-# LANGUAGE TransformListComp #-}

import GHC.Exts
import Data.List
import Data.Function (on)

process :: [(Integer, String)] -> [(String, [Integer])]
process list = [ (the y, x) | (x, y) <- list, then  group by y using groupWith ]

*Main> :load ListUtil.hs
[1 of 1] Compiling Main             ( ListUtil.hs, interpreted )
Ok, modules loaded: Main.
*Main> 
*Main> process [(1,"aa"),(1,"cc"),(2,"aa"),(3,"ff"),(3,"gg"),(1,"bb")]
[("aa",[1,2]),("bb",[1]),("cc",[1]),("ff",[3]),("gg",[3])]
*Main> 


Combine sorting and grouping
It is an enhancement to the problem 2.

Given a list of tuples like this:

dic = [(1,"aa"),(1,"cc"),(2,"aa"),(3,"ff"),(3,"gg"),(1,"bb")]

You have to group like below.

grp  = [(1,["aa","bb","cc"]), (2, ["aa"]), (3, ["ff","gg"])]

ListUtil.hs
{-# LANGUAGE TransformListComp #-}

import GHC.Exts
import Data.List
import Data.Function (on)

process :: [(Integer, String)] -> [(Integer, [String])]
process list = [(the a, b) |  let info = [ (x, y) | (x, y) <- list, then sortWith by y ], (a, b) <- info, then group by a using groupWith]

*Main> :load ListUtil.hs
[1 of 1] Compiling Main             ( ListUtil.hs, interpreted )
Ok, modules loaded: Main.
*Main> 
*Main> process [(1,"aa"),(1,"cc"),(2,"aa"),(3,"ff"),(3,"gg"),(1,"bb")]
[(1,["aa","bb","cc"]),(2,["aa"]),(3,["ff","gg"])]
*Main> 


then group using f
With this form of the group statement, f is required to simply have the type forall a. [a] -> [[a]], which will be used to group up the comprehension so far directly.

ListUtil.hs
{-# LANGUAGE TransformListComp #-}

import GHC.Exts
import Data.List

process = [ x|  x <- "hello", then group using subsequences]

*Main> :load ListUtil.hs
[1 of 1] Compiling Main             ( ListUtil.hs, interpreted )
Ok, modules loaded: Main.
*Main> 
*Main> process
["","h","e","he","l","hl","el","hel","l","hl","el","hel","ll","hll","ell","hell","o","ho","eo","heo","lo","hlo","elo","helo","lo","hlo","elo","helo","llo","hllo","ello","hello"]


ListUtil.hs
{-# LANGUAGE TransformListComp #-}

import GHC.Exts
import Data.List

process xs ys = [ (x, y) | x <- xs, y <- ys, then group using subsequences ]

*Main> process "ab" "cd"
[("",""),("a","c"),("a","d"),("aa","cd"),("b","c"),("ab","cc"),("ab","dc"),("aab","cdc"),("b","d"),("ab","cd"),("ab","dd"),("aab","cdd"),("bb","cd"),("abb","ccd"),("abb","dcd"),("aabb","cdcd")]
*Main> 
*Main> :load ListUtil.hs
[1 of 1] Compiling Main             ( ListUtil.hs, interpreted )
Ok, modules loaded: Main.
*Main> 
*Main> process "a" "cd"
[("",""),("a","c"),("a","d"),("aa","cd")]
*Main> 
*Main> process "ab" "c"
[("",""),("a","c"),("b","c"),("ab","cc")]
*Main> 
*Main> process "ab" "cd"
[("",""),("a","c"),("a","d"),("aa","cd"),("b","c"),("ab","cc"),("ab","dc"),("aab","cdc"),("b","d"),("ab","cd"),("ab","dd"),("aab","cdd"),("bb","cd"),("abb","ccd"),("abb","dcd"),("aabb","cdcd")]
*Main> 




Previous                                                 Next                                                 Home

No comments:

Post a Comment