2011-11-02 191 views
2

我已经挣扎了好几个小时,而且我弄不明白。Haskell自定义数据类型

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-> String。

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

总的来说这里是我想到: 发送[Run]和一个词来搜索,其中[Run] = [[Entries]]Word = String

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

所以,函数搜索应该检查发送的Word的长度,然后调用search'并发送与列表长度相等的条目列表关联的subList。

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

任何帮助将是太棒了。

回答

4

有两个单独的问题:

1.您应该应用defEntry如果你想要一个String。所以,search'的定义应该是这样的:

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

2.不明显,先验的,即搜索将始终准确地找到一个匹配。可能没有比赛,或许多比赛。 (据我所知,您可能希望您提供的数据只会导致一次匹配,但这种推理稍微超出了可以高效和静态执行的步骤)。因此,您的search'search函数应返回列表。该类型签名应该是这样的:

search' :: Word -> [Entry] -> [String] 
search :: [Run] -> Word -> [String] 

...,而事实上,如果你离开类型签名了,GHC会正好推断这些类型(最多类型同义词)。

编辑:为了解决这个问题,更新,你可能想是这样的:

search' searchWord subList = case [def x | x <- subList, wrd x == searchWord] of 
    [] -> "no match" 
    (match:_) -> match 

Learn You a Haskell有一个关于模式,如果你想了解更多的匹配部分。它也有一个关于lists and list comprehensions的部分,通常只是一个很好的教程。

但是,我强烈建议不要这样写search':这有点不诚实! (例如,作为search'的调用者,如何区分结果'搜索成功,翻译为“不匹配”,结果'搜索失败'?)

+0

为什么我要他们返回[字符串] ...如果我只想要一个完全匹配?而且,如何在代码中添加没有匹配的条件?我的理解是,一旦Haskell发现第一场比赛,它应该停止正在做的并返回...所以我不认为我需要担心多场比赛? – KevinCameron1337

+1

一次提出一个问题。如果你想要一次完全匹配,你必须自己处理其他案例。使用'case'语句,如'[] - >“当没有匹配时要返回的字符串的大小写匹配”; (匹配:_) - >匹配。 2.如果没有匹配,则不需要添加任何附加代码以返回空列表;它已经做到了。你的理解是不正确的。您可能想在任何您最喜欢的教程中查看列表解析部分。 –

+0

我不知道如何使用'case'语句。我会寻找一些例子。并审查列表解析。 – KevinCameron1337

1

嗯,让我们来看看。你有一个东西的列表,[a]。您有一些确定搜索是否成功的标准,a -> Bool。并且您想要在列表中执行搜索,返回元素类型值a。停止...霍格尔时间!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作为字段存取器,从Entry中提取def。但我们如何将这个应用到Maybe Entry

Stop ... Hoogle时间!我们有一个值,v :: Maybe a。我们有一个在普通的旧af :: 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,它只是使用默认值。否则,它使用Just构造函数内部的值f

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