data Edit =
Change Char Char|
Copy Char|
Delete Char|
Insert Char
deriving (Eq, Show)
cost :: [Edit] -> Int
cost edits
= length ( filter (\x -> x /= Copy) edits )
main :: IO()
main
= putStrLn ( show ( cost [Copy 'e', Copy 'x', Insert 'm', Insert 'o', Change 'e' 'u', Copy 't', Delete 'e', Change 'r' 'h'] ) )
我正在尝试使用代数数据类型来计算List的成本,每次编辑的成本为1,副本的成本为0。
我当前收到错误消息:
* Couldn't match type `Edit' with `Char -> Edit'
Expected type: [Char -> Edit]
Actual type: [Edit]
* In the second argument of `filter', namely `edits'
In the first argument of `length', namely
`(filter (\ x -> x /= Copy) edits)'
In the expression: length (filter (\ x -> x /= Copy) edits)
^^^^^
我看不到掌握代数类型,因此不胜感激
答案 0 :(得分:1)
Copy
是Edit
的构造函数,其一个字段类型为Char
,因此具有以下函数类型:
Copy :: Char -> Edit
实际上,使用{-# LANGUAGE GADTSyntax #-}
可以在定义中显式地编写每个构造函数的类型,您可能会更清楚地看到它:
data Edit where
Change :: Char -> Char -> Edit
Copy :: Char -> Edit
Delete :: Char -> Edit
Insert :: Char -> Edit
deriving (Eq, Show)
因此,传递给filter
的函数\x -> x /= Copy
具有以下推断类型,因为您正试图将x
与函数Copy
进行比较:< / p>
(Eq (Char -> Edit))
=> (Char -> Edit) -> Bool
filter
具有这种类型:
filter :: (a -> Bool) -> [a] -> [a]
由于推论a
等于Char -> Edit
,因此推断filter (\x -> x /= Copy)
的类型为:
(Eq (Char -> Edit))
=> [Char -> Edit] -> [Char -> Edit]
当然不是您想要的,这有两个原因-首先,它不表达您想要的内容(不是使用Copy
构造函数构造的编辑内容),其次,它可以无法工作,因为没有实例Eq (Char -> Edit)
可让您比较函数,也无法编写一个实例,因为函数不可比。
如果要检查在调用Edit
时是否使用Copy
构造了filter
类型的值,则应改用 pattern-matching 。一种简单的方法是编写一个函数:
isCopy :: Edit -> Bool
isCopy edit = case edit of
{- your implementation here -}
然后在filter
的情况下使用它:
filter (\x -> {- your condition here -})
并且它将根据需要输入[Edit] -> [Edit]
类型。除了编写单独的函数isCopy
之外,您还可以使用case
表达式编写此内联代码:
filter (\x -> case x of
{- your implementation here -})
解决此问题的另一种方法是通过编写函数cost1 :: Edit -> Int
将其分解为较小的部分,该函数返回单个编辑的成本:
cost1 :: Edit -> Int
cost1 edit = case edit of
Change _ _ -> 1
Copy _ -> 0
{- remaining cases -}
然后cost
可以使用map
或列表理解将cost1
应用于整个编辑列表,并获取结果的sum
。