-
Notifications
You must be signed in to change notification settings - Fork 50
Add Data.List.ZipList.transpose #58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ | |
module Data.List.ZipList | ||
( ZipList(..) | ||
, runZipList | ||
, transpose | ||
) where | ||
|
||
import Prelude | ||
|
@@ -13,9 +14,11 @@ import Control.Alternative (Alternative) | |
import Control.Plus (Plus) | ||
|
||
import Data.Foldable (Foldable, foldMap, foldl, foldr) | ||
import Data.List.Lazy (List(), repeat, zipWith) | ||
import Data.List.Lazy (List(), repeat, zipWith, fromFoldable, toUnfoldable) | ||
import Data.Monoid (Monoid, mempty) | ||
import Data.Traversable (Traversable, traverse, sequence) | ||
import Data.Foldable (Foldable) | ||
import Data.Unfoldable (Unfoldable) | ||
|
||
-- | `ZipList` is a newtype around `List` which provides a zippy | ||
-- | `Applicative` instance. | ||
|
@@ -25,6 +28,24 @@ newtype ZipList a = ZipList (List a) | |
runZipList :: forall a. ZipList a -> List a | ||
runZipList (ZipList xs) = xs | ||
|
||
-- | Transpose any structure which is both `Foldable` and `Unfoldable`, | ||
-- | via `ZipList`; note that `sequence` for `ZipList` is the same as | ||
-- | `transpose`. | ||
transpose :: forall f a. (Foldable f, Unfoldable f) => f (f a) -> f (f a) | ||
transpose = | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice implementation 😄 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my opinion, such a highly generalized implementation as the above There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My point is just that there is a difference between
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that I don't have to worry about the core library dependency graph, I won't make any suggestions about where I think this should go, I'll leave that up to you ;) I will say, though, that I don't see how this could go into Maybe we should just start with a version defined in terms of Come to think of it, why does There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, lol, of course. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Speaking of which, doesn't this diverge for empty input? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oops, yes it does. |
||
toZipList | ||
>>> map toZipList | ||
>>> sequence | ||
>>> map fromZipList | ||
>>> fromZipList | ||
|
||
where | ||
toZipList :: forall a'. f a' -> ZipList a' | ||
toZipList = ZipList <<< fromFoldable | ||
|
||
fromZipList :: forall a'. ZipList a' -> f a' | ||
fromZipList = toUnfoldable <<< runZipList | ||
|
||
instance showZipList :: (Show a) => Show (ZipList a) where | ||
show (ZipList xs) = "(ZipList " ++ show xs ++ ")" | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
module Test.Data.List.ZipList (testZipList) where | ||
|
||
import Prelude | ||
import Control.Monad.Eff (Eff()) | ||
import Control.Monad.Eff.Console (CONSOLE(), log) | ||
import Data.Foldable | ||
import Data.Monoid.Additive | ||
import Data.List.Lazy as LazyList | ||
import Data.List.ZipList (ZipList(..), transpose) | ||
import Data.Maybe (Maybe(..), isNothing) | ||
import Data.Maybe.Unsafe (fromJust) | ||
import Data.Tuple (Tuple(..)) | ||
import Data.Array as Array | ||
import Test.Assert (ASSERT(), assert) | ||
|
||
testZipList :: forall eff. Eff (assert :: ASSERT, console :: CONSOLE | eff) Unit | ||
testZipList = do | ||
log "ZipList Applicative instance should be zippy" | ||
testZipWith (+) [1,2,3] [4,5,6] | ||
testZipWith (*) [1,2,3] [4,5,6] | ||
testZipWith const [1,2,3] [4,5,6] | ||
|
||
log "ZipList.transpose" | ||
assert $ transpose [[1,2,3],[4,5,6],[7,8,9]] == [[1,4,7],[2,5,8],[3,6,9]] | ||
|
||
testZipWith :: forall a b c eff. (Eq c) => (a -> b -> c) -> Array a -> Array b -> Eff (assert :: ASSERT, console :: CONSOLE | eff) Unit | ||
testZipWith f xs ys = | ||
assert $ (f <$> l xs <*> l ys) == l (Array.zipWith f xs ys) | ||
|
||
-- Shortcut for constructing a ZipList | ||
l :: forall a. Array a -> ZipList a | ||
l = ZipList <<< LazyList.fromFoldable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these overloaded functions have their place, but I'd prefer to expose a
List
version too, since we're going via that function anyway.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about this, but what about name collisions? There's always straight
sequence
if you want to avoid all the other stuff, eg for performance.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm just concerned that a beginner won't know to use
sequence
, and may not understand the more general type signature.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already have generalized type signatures for all kinds of things, though?
foldr
,replicate
,(<>)
, even(+)
and(*)
.Just so that we're on the same page - are you suggesting we put specialized versions of
transpose
intoData.List
andData.List.Lazy
, as well as this generalized version here?