简体   繁体   中英

What is needed to get my custom ZipList applicative instance to compile?

Here is my custom List class used to create a custom ZipList class. I want to create a ZipList' applicative instance.

import Control.Applicative

data List a =
  Nil
  | Cons a (List a)
  deriving (Eq, Show)

instance Functor List where
  fmap f (Cons x xs) = Cons (f x) (fmap f (Cons (head' xs) (tail' xs)))
  fmap _ Nil = Nil

instance Applicative List where
  pure x = Cons x Nil
  (<*>) fs xs = Cons (head' fs $ head' xs) ((<*>) (tail' fs) (tail' xs))

head' :: List a -> a
head' (Cons a _) = a

tail' :: List a -> List a
tail' (Cons _ l) = l

take' :: Int -> List a -> List a
take' 0 _ = Nil
take' _ Nil = Nil
take' i xs = Cons (head' xs) (take' (i-1) (tail' xs))

newtype ZipList' a =
  ZipList' (List a)
  deriving (Eq, Show)

instance Functor ZipList' where
  fmap f (ZipList' xs) = ZipList' $ fmap f xs

instance Applicative ZipList' where
  pure x = ZipList' (Cons x Nil)
  (<*>) fs xs = ZipList' (go fs xs)
    where go gs ys = Cons (head' gs $ head' ys) (go (tail' gs) (tail' ys))
          go Nil _ = Nil
          go _ Nil = Nil

The error I am getting is:

chap17/ZipList_applicative.hs:38:30: Couldn't match expected type ‘List (r0 -> b)’ …
                with actual type ‘ZipList' (a -> b)’
    Relevant bindings include
      xs :: ZipList' a
        (bound at /Users/ebs/code/haskell/book/chap17/ZipList_applicative.hs:38:12)
      fs :: ZipList' (a -> b)
        (bound at /Users/ebs/code/haskell/book/chap17/ZipList_applicative.hs:38:9)
      (<*>) :: ZipList' (a -> b) -> ZipList' a -> ZipList' b
        (bound at /Users/ebs/code/haskell/book/chap17/ZipList_applicative.hs:38:3)
    In the first argument of ‘go’, namely ‘fs’
    In the first argument of ‘ZipList'’, namely ‘(go fs xs)’
chap17/ZipList_applicative.hs:38:33: Couldn't match expected type ‘List r0’ …
                with actual type ‘ZipList' a’
    Relevant bindings include
      xs :: ZipList' a
        (bound at /Users/ebs/code/haskell/book/chap17/ZipList_applicative.hs:38:12)
      fs :: ZipList' (a -> b)
        (bound at /Users/ebs/code/haskell/book/chap17/ZipList_applicative.hs:38:9)
      (<*>) :: ZipList' (a -> b) -> ZipList' a -> ZipList' b
        (bound at /Users/ebs/code/haskell/book/chap17/ZipList_applicative.hs:38:3)
    In the second argument of ‘go’, namely ‘xs’
    In the first argument of ‘ZipList'’, namely ‘(go fs xs)’
Compilation failed.

It says that it expects a List (r0 -> b) type from go, not ZipList'. I do not get why, go returns a List, not a ZipList'...

Your go takes ZipList as input, but in (<*>) fs xs xs and fs are ZipList' s. You should unwrap the newtype:

ZipList' fs <*> ZipList' xs = ZipList' (go fs xs)

Also, your go is wrong. It fails with a runtime error whenever the program evaluates an empty list in either arguments, because the go gs ys case matches everything, and the cases after it are unreachable. You should instead do something like this:

go (Cons f fs) (Cons x xs) = Cons (f x) (go fs xs)
go _ _ = Nil

As a general rule, you should avoid head , tail , and other partial functions (ie functions that possibly throw exceptions). Pattern matching on Cons x xs binds both the head and the tail, so there isn't much use for head and tail thereafter. It's very rare that the use of partial functions is truly justified.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM