Пользовательские типы данных Haskell

#haskell #hash #types

#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 .

Но я ожидал, что type будет строкой. Я не знаю, почему он думает, что мне нужен только символ.

В общем, вот что я ожидаю: отправьте [Run] и слово для поиска, где [Run] = [[Entries]] и Word = String

они [Run] должны быть отформатированы так, чтобы все записи [Run]!!0 имели длину 0, [Run]!!1 длину 1 и т.д.

Итак, функция search должна проверять длину отправленного слова, затем вызывать search’ и отправлять ему подсписок, связанный со списком записей, которые имеют ту же длину, что и слово.

После того, как внутри search’я просто хочу выполнить линейный поиск по списку wrd == Word , а затем вернуть def этого слова.

любая помощь была бы фантастической.

Ответ №1:

Есть две отдельные проблемы:

1. Вы должны обратиться def к an Entry , если хотите 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
  

Узнайте, что в Haskell есть раздел о сопоставлении шаблонов, если вы хотите узнать больше. В нем также есть раздел, посвященный спискам и пониманию списков, и, как правило, это просто хороший учебник.

Однако я настоятельно не советую писать search' так: это немного нечестно! (Например, как вызывающий search' , как я могу отличить результат «поиск завершен успешно, а перевод «не соответствует»» и результат «поиск не удался»?)

Комментарии:

1. Почему я хочу, чтобы они возвращали [String] … если я хочу только одно точное совпадение? И как мне добавить условия для отсутствия совпадений в коде? Я понимаю, что как только Haskell найдет первое совпадение, он должен прекратить то, что делает, и вернуться… так что я не думаю, что мне нужно беспокоиться о нескольких совпадениях?

2. По одному вопросу за раз. 1. Если вам нужно одно точное совпадение, вы должны обработать другие случаи самостоятельно. Используйте case оператор, подобный case matches of [] -> "a string you want to return when there are no matches"; (match:_) -> match . 2. Вам не нужно добавлять какой-либо дополнительный код, чтобы возвращать пустой список, когда совпадений нет; он уже это делает. 3. Ваше понимание неверно. Возможно, вы захотите просмотреть раздел о понимании списков в любом учебном пособии, которое вам больше нравится.

3. я понятия не имею, как использовать case оператор. я поищу несколько примеров. И просмотрите список.

4. Смотрите Новую функцию поиска выше. это говорит об ошибке синтаксического анализа в шаблоне для части «нет совпадения»

5. @Special—k Хорошо, я обновил ответ. Однако в будущем вам следует задавать новый вопрос для каждой отдельной проблемы, которую вы пытаетесь решить; в противном случае вопросы и ответы могут сбивать с толку.

Ответ №2:

Хм, давайте посмотрим. У вас есть список вещей, [a] . У вас есть некоторые критерии для определения, был ли поиск успешным или нет, a -> Bool . И вы хотите выполнить поиск по списку, возвращая значение типа элемента a . Остановите … время ожидания! (a -> Bool) -> a» rel=»nofollow»>Хуглинг [a] -> (a -> Bool) -> a , главный хит find :: (a -> Bool) -> [a] -> Maybe a . Единственная загвоздка в том, что он возвращает a Maybe a : он либо найдет Just something , либо Nothing . Я бы сказал, что это подходящее обновление для вашей search функции.

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

Поскольку мы изменили контракт на search для создания a 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 . Но как мы применим это к a Maybe Entry ?

Остановите … время ожидания! У нас есть значение, v :: Maybe a . У нас есть функция, которая работает с простыми старыми a значениями, f :: a -> b . Мы хотим каким-то образом применить f к v , получая результат типа b . (a -> b) -> b» rel=»nofollow»>Просматривая Maybe a -> (a -> b) -> b , я вижу два хороших варианта.

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

maybe Функция принимает функцию и значение maybe, а также значение по умолчанию. Если значение 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
  

Если вы не знакомы с функторами, я настоятельно рекомендую изучить класс типов Haskell> the Functor. Maybe — это функтор, что означает, что мы можем использовать fmap значения maybe.

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