3

私は大学の科目で 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

この質問では、そのような HTML 表現で font_tag のすべてのインスタンスをカウントする Haskell 関数 'num_font_tags' を作成するよう求めています。以下は私の答えです。頭を壁に突き合わせるのに約1時間かかりましたが、問題なくコンパイルされ、解決策であると思います。

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 型を受け入れる関数がさらに 2 つ必要でした。

それは私がこの質問をする必要があった方法ですか?それとも、3 つの機能を使用することで、やり過ぎているのでしょうか。1本で出来ますか?私の主な質問は、Haskell の性質について、これをより簡単にする何かが欠けているのでしょうか?

4

2 に答える 2

6

そのような関数は 1 つだけ必要で、他の関数は単純に次のように削減できます。

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

単一の値からリストを簡単に取得できるため、他の 2 つのそれぞれから残りの関数を派生させることもできますが、いずれにせよ、ある時点で a を検査する必要があるため、構築するベース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 resp. [HTML]またはsum . map num_font_tag_singleresp を使用します。sum . map num_font_tag_single . concatほとんど個人の好みですが、対象は関数なので

num_font_tags :: HTML -> Int

それに名前を付ける (そしてnum_font_tags . concat再帰で使用する) のは自然なことです。

于 2013-03-29T13:41:07.367 に答える
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パッケージを使用します。2 番目の解は、次の方法で得られる「折りたたみ」の長さを取ります

  1. HTML リストの各要素を調べます。
  2. それ自体を含む、各 HTML_element の HTML_element サブコンポーネントのリストを調べます。
  3. そのようなすべてのリストの各 HTML_element を調べます。
  4. HTML_fonts ではないものをスキップします。

partsトラバーサルと関数は、型クラスuniverseのインスタンスであるデータ型でのみ使用できますPlated。で実装しましたが、これにはデータ型がanduniplateのインスタンスである必要があります。これらは、言語拡張機能を使用して導出できます。DataTypeableDeriveDataTypeable

于 2013-03-29T16:37:03.250 に答える