0

compress xs@(_:_:_) = (ifte <$> ((==) <$> head <*> head.tail) <$> ((compress.).(:) <$> head <*> tail.tail) <*> ((:) <$> head <*> compress.tail) ) xs

导致类型错误,但我不明白为什么。它应该相当于

compress xs@(_:_:_) = (ifte (((==) <$> head <*> head.tail) xs) (((compress.).(:) <$> head <*> tail.tail) xs) (((:) <$> head <*> compress.tail) xs))

,这不是。

注意ifte = (\ x y z -> if x then y else z)<$><*>来自Control.Applicative

编辑:错误是:

Couldn't match expected type `[a]' with actual type `[a] -> [a]'
    In the expression:
        (ifte <$> ((==) <$> head <*> head . tail)
     <$>
       ((compress .) . (:) <$> head <*> tail . tail)
   <*>
     ((:) <$> head <*> compress . tail))
      $ xs
    In an equation for `compress':
        compress xs@(_ : _ : _)
          = (ifte <$> ((==) <$> head <*> head . tail)
         <$>
           ((compress .) . (:) <$> head <*> tail . tail)
       <*>
         ((:) <$> head <*> compress . tail))
          $ xs

我在尝试编写九十九个 Haskell 问题的第 8 题的无点解决方案时遇到了这个问题。我试图通过修改我写的有意义的解决方案来做到这一点,这是

compress::Eq a => [a]->[a]
compress [] = []
compress (x:[]) = (x:[])
compress (x:y:xs) = ifte ((==) x y) (compress (x:xs)) (x:(compress (y:xs)))
4

3 回答 3

6

首先,缩进。其次,考虑使用一些变量。

即使使用更合理的格式,您也可以看到它

compress =
  ifte <$> ((==) <$> head <*> head.tail)
       <$> ((compress.).(:) <$> head <*> tail.tail)
       <*> ((:) <$> head <*> compress.tail)

什么时候应该

compress =
  ifte <$> ((==) <$> head <*> head.tail)
       <*> ((compress.).(:) <$> head <*> tail.tail)
       <*> ((:) <$> head <*> compress.tail)

第三,就算你一定是高深莫测,又如何

compress (x:r@(y:_)) = ifte (x==y) id (x:) $ compress r

或者,免费点

compress = map fst . filter (uncurry (/=)) . (zip <$> id <*> tail)
于 2011-10-22T21:13:46.207 回答
5

这是您以更具可读性的方式编写的代码

{-# LANGUAGE NoMonomorphismRestriction #-}
import Control.Applicative

u = ((==) <$> head <*> head.tail)
v = ((compress.).(:) <$> head <*> tail.tail)
w = ((:) <$> head <*> compress.tail)

ifte = (\ x y z -> if x then y else z) 

--compress xs@(_:_:_) = (ifte <$> u <$> v <*> w) xs
compress xs@(_:_:_) = (ifte (u xs) (v xs) (w xs))

我希望你现在看到错误 - 正确的版本是

--compress xs@(_:_:_) = (ifte <$> u <*> v <*> w) xs
于 2011-10-22T20:58:10.703 回答
2

这与已经说过的非常相似,但请放过我一会儿,让我向您宣讲类型的价值。

import Control.Applicative

ifte :: Bool -> a -> a -> a
ifte b t f = if b then t else f

compress :: Eq a => [a] -> [a]
-- compress = ifte <$> cond <$> t <*> f
-- We will leave compress undefined so we can load this into ghci.
-- After some trial and error it is clear that this is the part
-- that doesn't type check
compress = undefined

cond :: Eq a => [a] -> Bool
cond = (==) <$> head <*> head . tail

t :: Eq a => [a] -> [a]
t = (compress .) . (:) <$> head <*> tail . tail

f :: Eq a => [a] -> [a]
f = (:) <$> head <*> compress . tail

在这里,我将其拆分出来,正如 Brandon 所提到的,此时您应该看到错误在于使用<$>where <*>should be。随着你不断学习应用风格,你会熟悉这个概念,你的表达式通常有一个单一<$>的,后面跟着一个任意的 # of <*>

f <$> a <*> b <*> c <*> d <*> ...

不过,忽略这种见解,我暂时给每个子表达式一个类型和一个 TLD。这让我可以将文件加载到 ghci 并玩一下。

ghci> :t ifte <$> cond <$> t <*> f
... Eq a => [a] -> [a] -> [a]

怎么回事???是打字声???它应该给出一个错误,但显然这个表达式是a-OK。或者是吗?请注意,此类型签名与我们想要的不匹配compress

ghci> :t compress
... Eq a => [a] -> [a]

子表达式与我们期望的类型签名匹配,编译器没有向我们吐槽就证明了这一点。既然是这样,问题显然出在我们结合它们的方式上。那么我们想要在这里结合哪些部分呢?忽略 Eq 约束:

ifte :: Bool -> [a] -> [a] -> [a]
cond :: [a] -> Bool
t    :: [a] -> [a]
f    :: [a] -> [a]

-- desired result
     :: [a] -> [a]

在这里,我做了iftefor[a]而不是 any的琐碎专业化a。关系很明确: 的输出类型cond,tf的输入类型匹配ifte。我们只需要将所有这三个表达式都输入相同的内容[a]。认识到这(input ->)是适用的,我们概括:

arg1 :: (a -> b -> c -> d)
arg2 :: f a
arg3 :: f b
arg4 :: f c
res  :: f d

-- for our case,
-- f = ([a] ->)
-- a = Bool
-- b = [a]
-- c = [a]
-- d = [a]

停止......胡歌时间!Hoogling(a -> b -> c -> d) -> f a -> f b -> f c -> f d,我们立即发现liftA3,它的定义并不奇怪:

liftA3 f a b c = f <$> a <*> b <*> c
于 2011-10-22T23:11:32.183 回答