Haskell自定义数据类型

时间:2011-11-02 17:33:20

标签: haskell hash types

我已经挣扎了几个小时,我无法弄明白。

module Main where
import Data.List
import Data.Function

type Raw = (String, String)

icards = [("the", "le"),("savage", "violent"),("work", "travail"),("wild", "sauvage"),
("chance", "occasion"),("than a", "qu'un"),("expensive.", "cher."),("saves", "en 
vaut"),("time", "temps"),("in", "<`a>"), ("worse", "pire"),("{", "{"),("A", "Un"),
("stitch", "point"),("crime;", "crime,"),("a", "une"),("nine.", "cent."),("It's", 
"C'est"),("all","tout"),("rare", "rare"),("you", "vous"),("Abandon","Abandonnez"),
("stash", "planquer"),("Everything", "Tout!ce!qui!est"),("who enter.", "qui entrez."),
("Zazie", "Zazie"),("is", "est"),("cat", "chat"),("it's", "c'est"),("raisin", "raisin 
sec"),("hope,", "espoir,"),("mistake.", "faute."),("luck", "chance"),("blueberry", 
"myrtille"),("I!took", "J'ai pris"),("that", "qui"),("a!chance.", "des risques."),
("drink", "boisson"),("Live", "Vivre"),("regrets.", "regrets."),("stone", "pierre"),
("broke", "a fait d<e'>border"),("without", "sans"),("The!straw", "La goutte d'eau"),
("camel's!back.", "vase.")]


data Entry = Entry {wrd, def :: String, len :: Int, phr :: Bool}
        deriving Show

-- English-to-French, hash-table section

entries :: [Entry]
entries = map (\(x, y) -> Entry x y (length x) (' ' `elem` x)) icards

type Run = [Entry]

maxl = maximum [len e | e <- entries]

runs :: [Run]
runs = f 0 $ groupBy ((==) `on` len) $ sortBy (compare `on` len) entries
  where f _ [] = []
        f i (r @ (Entry {len = l} : _) : rs) | i == l = r  : f (i + 1) rs
        f i                              rs           = [] : f (i + 1) rs

type Word = String

search' :: Word -> [Entry] -> String
search' searchWord subList 
search' _ [] = "unknown"
search' ([def x | x <- subList,  (wrd x) == searchWord])==[] = "no match"
search' = [def x | x <- subList,  (wrd x) == searchWord]

--search' searchWord subList = (def | x <- subList,  (wrd x) == searchWord)
--search' searchWord subList = [def x::String | x <- subList,  (wrd x) == searchWord]
--search' searchWord [subList] = [def | x <- subList,  (wrd x) == searchWord]
--search' searchWord subList = [def | x <- subList,  (wrd x) == searchWord]
--search' searchWord subList = [def x | x <- subList,  (wrd x) == searchWord]
--search' searchWord subList = [x->def | x <- subList,  (x->wrd) == searchWord]

search :: [Run] -> Word -> String
search runList searchWord = search' searchWord $ runList!!wrdLen
                     where wrdLen = (length searchWord)

我需要搜索'功能的帮助。 GHCi会告诉我预期的类型是char ...而实际类型是Entry-&gt;字符串。

但我希望type是字符串。我不知道为什么它认为我只想要一个字符。

总的来说,这就是我的期望: 发送[Run]和Word搜索,其中[Run] = [[Entries]]Word = String

[Run]应格式化,以便[Run]!!0中的所有条目的长度为0,[Run]!!1的长度为1等。

因此,函数搜索应检查发送的Word的长度,然后调用search'并将与该列相关的子列表发送给与该单词具有相同长度的条目。

进入搜索后'我只想对wrd == Word的列表进行线性搜索,然后返回该单词的def。

任何帮助都会很棒。

2 个答案:

答案 0 :(得分:4)

有两个不同的问题:

1。如果您需要def,则应将Entry应用于String。因此,search'的定义应如下所示:

search' searchWord subList = [def x | x <- subList, wrd x == searchWord]

2。先验并不明显,搜索总能找到一个匹配。可能没有比赛或许多比赛。 (我知道你可能希望你提供的数据只会产生一个匹配,但这种推理有点超出了有效和静态的优势。)所以,你的search'和{{1函数应该返回列表。类型签名应如下所示:

search

...而且,实际上,如果你关闭类型签名,GHC将完全推断出那些类型(最多可以输入同义词)。

编辑:要解决更新后的问题,您可能需要以下内容:

search' :: Word -> [Entry] -> [String]
search :: [Run] -> Word -> [String]
如果您想了解更多,

Learn You a Haskell有一个关于模式匹配的部分。它还有lists and list comprehensions部分,通常只是一个很好的教程。

但是,我强烈建议不要这样写search' searchWord subList = case [def x | x <- subList, wrd x == searchWord] of [] -> "no match" (match:_) -> match :这有点不诚实! (例如,作为search'的调用者,我如何区分结果'搜索成功,翻译是“不匹配”'和结果'搜索失败'?)

答案 1 :(得分:1)

嗯,我们来看看。你有一个东西列表[a]。您有一些标准可用于确定搜索是否成功,a -> Bool。并且您希望在列表上执行搜索,返回元素类型a的值。停止...... Hoogle时间! Hoogling [a] -> (a -> Bool) -> a,排名最高的是find :: (a -> Bool) -> [a] -> Maybe a。唯一的问题是它会返回Maybe a:它会找到Just somethingNothing。我说这是适用于search功能的升级。

search :: [Run] -> Word -> Maybe Entry
search runList searchWord = find (\x -> wrd x == searchWord) $ runList!!wrdLen
  where wrdLen = (length searchWord)

由于我们已将search的合同更改为生成Maybe Entry而不是简单的String,因此如果您之前使用此类帐号:

doStuff (search runList searchWord)

您现在必须考虑搜索失败的可能性。

case search runList searchWord of
  Just foundWord -> doStuff (def foundWord)
  Nothing        -> doSomethingElse

如果您完全确定搜索永远不会失败,您可以使用fromJust

打开它。
doStuff (fromJust $ def $ search runList searchWord)

虽然通常不鼓励使用fromJust


现在,还有一件事。您说您只想返回def,而不是整个Entry。如您所知,我们可以使用def :: Entry -> String作为字段访问器从def中提取Entry。但是我们如何将其应用于Maybe Entry

停止...... Hoogle时间!我们有一个值v :: Maybe a。我们有一个适用于普通旧a值的函数f :: a -> b。我们希望以某种方式将f应用于v,从而产生类型b的结果。 Hoogling Maybe a -> (a -> b) -> b,我看到两个不错的选择。

maybe :: b -> (a -> b) -> Maybe a -> b
maybe n _ Nothing = n
maybe _ f (Just x) = f x

maybe函数采用函数和可能的值,还有默认值。如果可能的值结果为Nothing,则它只使用默认值。否则,它在f构造函数内部的值上使用函数Just

search :: [Run] -> Word -> String
search runList searchWord = search' (\x -> wrd x == searchWord) $ runList!!wrdLen
  where wrdLen = (length searchWord)

search' :: (Entry -> Bool) -> [Entry] -> String
search' f es = maybe "not found" def $ find f es
-- or eta reduce: search' = maybe "not found" def . find

这个解决方案没问题,但我更喜欢下一个。

fmap :: Functor f => (a -> b) -> f a -> f b

如果您不熟悉仿函数,我强烈推荐Learn you a Haskell > the Functor typeclass。也许是一个仿函数,这意味着我们可以使用fmap来表示可能的值。

search' :: (Entry -> Bool) -> [Entry] -> Maybe String
search' f es = fmap def $ find f es