功能输入类型

时间:2013-03-29 13:11:53

标签: haskell

我正在大学学习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性质的内容,这会使这更简单?

2 个答案:

答案 0 :(得分:6)

您只需要一个这样的功能,其他功能可以简单地简化为

num_font_tag_single :: HTML_element -> Int

summap

如你所愿,你有

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包。 第二个解决方案采用

获得的'折叠'的长度
  1. 浏览HTML列表的每个元素。
  2. 浏览每个HTML_element的HTML_element子组件列表,包括其自身。
  3. 浏览每个此类列表的每个HTML_element。
  4. 跳过非HTML_fonts的内容。
  5. parts遍历和universe函数仅适用于Plated类型类实例的数据类型。我使用uniplate实现了它,它需要数据类型为DataTypeable的实例;这些可以使用DeriveDataTypeable语言扩展名派生。