1

I'm in the process of learning applicative functors in Haskell from learn-you-a-haskell book. But whenever I try to type in the following code into ghci:

:{
instance Applicative ZipList where
        pure x = ZipList (repeat x)
        ZipList fs <*> ZipList xs = ZipList (zipWith (\f x -> f x) fs xs)
:}

I get three errors:

<interactive>:137:22: error:
    Not in scope: type constructor or class ‘ZipList’

<interactive>:139:9: error:
    Not in scope: data constructor ‘ZipList’

<interactive>:139:24: error:
    Not in scope: data constructor ‘ZipList’ 

I tried loading:

import Data.List
import Data.Char

I tried searching for ZipList without success.

I tried running the next few expressions without instance declaration:

getZipList $ (+) <$> ZipList [1,2,3] <*> ZipList [100,100,100]

But they also fail with the following errors:

<interactive>:142:1: error:
    Variable not in scope: getZipList :: f0 Integer -> t

<interactive>:142:22: error:
    Data constructor not in scope: ZipList :: [Integer] -> f0 Integer

<interactive>:142:42: error:
    Data constructor not in scope: ZipList :: [Integer] -> f0 Integer

I also tried searching and found this answer: Haskell ZipList Applicative But it doesn't help me.

Ari Fordsham
  • 2,437
  • 7
  • 28
Andrea
  • 153
  • 1
  • 11
  • 1
    It's in [`Control.Applicative`](https://hackage.haskell.org/package/base-4.15.0.0/docs/Control-Applicative.html#t:ZipList) but it already has an `Applicative` instance! – Iceland_jack Aug 04 '21 at 11:25
  • If I do ```import Control.Applicative.ZipList```, I get Could not find module ‘Control.Applicative.ZipList’ error – Andrea Aug 04 '21 at 11:41
  • 3
    Don't write the `.ZipList` part, `import Control.Applicative` is enough as you are importing `ZipList` from `Control.Applicative`. You can also write `import Control.Applicative (ZipList(..))` to only import the `ZipList` type, and everything bundled with it (the `ZipList` constructor, and the `getZipList` field accessor) – Iceland_jack Aug 04 '21 at 11:43
  • 2
    In the future you can search on [Hoogle](https://hoogle.haskell.org/?hoogle=ZipList) which is like Google for Haskell types or you can search within Hackage `ZipList site:hackage.haskell.org/` – Iceland_jack Aug 04 '21 at 12:04

1 Answers1

2

ZipList already exists in Control.Applicative and uses the Applicative instanced defined there. You can't redefine that instance.

>> import Control.Applicative
>> getZipList $ (+) <$> ZipList [1,2,3] <*> ZipList [100,100,100]
[101,102,103]
>> getZipList $ liftA2 (+) (ZipList [1,2,3]) (ZipList [100,100,100])
[101,102,103]

To define your own you must define a new ZipList' that we read "ZipList prime":

-- >> getZipList' $ (+) <$> ZipList' [1,2,3] <*> ZipList' [100,100,100]
-- [101,102,103]
newtype ZipList' a = ZipList' { getZipList' :: [a] }

instance Functor ZipList' where
  fmap f (ZipList' as) = ZipList' (fmap f as)

instance Applicative ZipList' where
  pure a = ZipList' (repeat a)

  ZipList' fs <*> ZipList' xs = ZipList' (zipWith (\f x -> f x) fs xs)

You can also derive Functor. I recommend writing instance signatures for fmap, pure, (<*>):

{-# Language DeriveFunctor #-}
{-# Language DerivingStrategies #-}
{-# Language InstanceSigs #-}

import Control.Applicative (liftA2)

newtype ZipList' a = ZipList' { getZipList' :: [a] }
  deriving
  stock Functor

-- instance Functor ZipList' where
--   fmap :: (a -> a') -> (ZipList' a -> ZipList' a')
--   fmap f (ZipList' as) = ZipList' (fmap f as)

instance Applicative ZipList' where
  pure :: a -> ZipList' a
  pure a = ZipList' (repeat a)

  (<*>) :: ZipList' (a -> b) -> ZipList' a -> ZipList' b
  ZipList' fs <*> ZipList' xs = ZipList' (zipWith ($) fs xs)

  liftA2 :: (a -> b -> c) -> (ZipList' a -> ZipList' b -> ZipList' c)
  liftA2 (·) (ZipList' as) (ZipList' bs) = ZipList' (zipWith (·) as bs)

You can write (\f x -> f x) as ($) or id.

Iceland_jack
  • 6,848
  • 7
  • 37
  • 46
  • Yep, ```import Control.Applicative ``` works. I was trying to import it directly by doing ```import Control.Applicative.ZipList``` – Andrea Aug 04 '21 at 11:44
  • Haskell is tough and it took me many attempts to get comfotable with it. To gve context: lists can be applicative functors in (at least) *two*, 1. non-determinism (`Applicative []`) and 2. zipping (`Applicative ZipList`) but lists can only be given a single instance so non-determinism is the default: `liftA2 (+) [1,2,3] [100,100,100]` = `[101,101,101,102,102,102,103,103,103]` – Iceland_jack Aug 04 '21 at 12:01
  • *comfortable *give – Iceland_jack Aug 04 '21 at 12:09