我正在大学学习Haskell - 这是我在业余时间做过的一个研讨会问题,你可能会猜到我正在努力解决Haskell中的类型问题。我已经完成了这个问题,但是没有答案被发表但我仍然非常想知道这是否是最好的方法。
以下是问题中提供的HTML的基本表示
type HTML = [HTML_element]
data HTML_element
= HTML_text String
| HTML_font Font_tag HTML
| HTML_p HTML
| HTML_ul [HTML]
| HTML_ol [HTML]
data Font_tag = Font_tag (Maybe Int) (Maybe String) (Maybe Font_color)
data Font_color
= Colour_name String
| Hex Int
| RGB Int Int Int
该问题要求构造一个Haskell函数'num_font_tags',它将计算这种HTML表示中font_tag的所有实例。接下来是我的回答,这让我花了整整一个小时的时间将我的头撞在墙上,但它编译得很好,我认为这是一个解决方案:
num_font_tags :: HTML -> Int
num_font_tags [] = 0
num_font_tags (x:xs) = num_font_tag_single x + num_font_tags xs
num_font_tags_list :: [HTML] -> Int
num_font_tags_list [] = 0
num_font_tags_list (x:xs) = num_font_tags x + num_font_tags_list xs
num_font_tag_single :: HTML_element -> Int
num_font_tag_single (HTML_text _) = 0
num_font_tag_single (HTML_font _ html) = num_font_tags html
num_font_tag_single (HTML_p html) = num_font_tags html
num_font_tag_single (HTML_ul html) = num_font_tags_list html
num_font_tag_single (HTML_ol html) = num_font_tags_list html
最初我以为我只需要第一个函数,但我遇到了问题,因为它只接受HTML类型,但后来又需要两个函数 - 一个接受[HTML]类型,一个接受HTML_element类型。
我是否真的需要这样做?或者我是通过3个功能来实现的。可以用一个吗?我的主要问题是 - 我是否遗漏了一些关于Haskell性质的内容,这会使这更简单?
答案 0 :(得分:6)
您只需要一个这样的功能,其他功能可以简单地简化为
num_font_tag_single :: HTML_element -> Int
sum
和map
。
如你所愿,你有
num_font_tags xs = sum $ map num_font_tag_single xs
和
num_font_tag_list xs = sum $ map num_font_tags xs
-- = sum . map num_font_tag_single $ concat xs
您还可以从其他两个函数中派生剩余函数,因为您可以轻松地从单个值中获取列表,但无论如何您需要在某个时刻检查HTML_element
,因此它是最好的使num_font_tag_single
成为构建的基础。
你有
num_font_tag_single (HTML_font _ html) = num_font_tags html
应该是
num_font_tag_single (HTML_font _ html) = num_font_tags html + 1
-- ^^^
或者您可以将功能简化为num_font_tag_single _ = 0
。
除此之外,这基本上是唯一的方法,无论你是否在HTML_element
s的包含列表中命名总结字体标签数量的函数。 [HTML]
或使用sum . map num_font_tag_single
resp。 sum . map num_font_tag_single . concat
主要取决于个人偏好,但由于目标是函数
num_font_tags :: HTML -> Int
很自然地给它一个名字(并在递归中使用num_font_tags . concat
)。
答案 1 :(得分:0)
在Haskell中,每个问题都有一个简短,令人敬畏且难以理解的抽象解决方案:
{-# LANGUAGE DeriveDataTypeable #-}
import Control.Lens
import Data.Data
import Data.Data.Lens
type HTML = [HTML_element]
data HTML_element
= HTML_text String
| HTML_font Font_tag HTML
| HTML_p HTML
| HTML_ul [HTML]
| HTML_ol [HTML]
deriving (Data, Typeable)
data Font_tag = Font_tag (Maybe Int) (Maybe String) (Maybe Font_color)
deriving (Data, Typeable)
data Font_color
= Colour_name String
| Hex Int
| RGB Int Int Int
deriving (Data, Typeable)
instance Plated HTML_element where
plate = uniplate
isFont :: HTML_element -> Bool
isFont (HTML_font _ _) = True
isFont _ = False
num_font_tags :: HTML -> Int
num_font_tags = length . filter isFont . concatMap universe
num_font_tags2 :: HTML -> Int
num_font_tags2 = lengthOf $ each . parts . each . filtered isFont
这些使用Control.Lens包。 第二个解决方案采用
获得的'折叠'的长度 parts
遍历和universe
函数仅适用于Plated
类型类实例的数据类型。我使用uniplate
实现了它,它需要数据类型为Data
和Typeable
的实例;这些可以使用DeriveDataTypeable
语言扩展名派生。