Как реализовать функцию поиска с помощью функции фильтра? - PullRequest
0 голосов
/ 15 апреля 2019

Я делаю упражнение, чтобы попрактиковаться в навыках Хаскеля.Моя задача - реализовать функцию Haskell find самостоятельно с помощью функции filter.

Я уже реализовал функцию find без функции filter (см. Кодовый блок ниже), но теперь моя проблема заключается в том, чтореализовать его с помощью функции filter.

-- This is the `find` function without `filter` and it's working for me.

find1 e (x:xs)= if e x then x
        else find1 e xs

-- This is the find function with the filter function 

find2 e xs = filter e xs

Результат find1 правильный

*Main> find1(>4)[1..10]
Output : [5].

Но моя актуальная задача написать функцию сфильтр дает мне

*Main> find2(>4)[1..10]
Output : [5,6,7,8,9,10].

Мой требуемый результат для find2 - это результат find1.

1 Ответ

2 голосов
/ 15 апреля 2019

Чтобы «вырезать список», чтобы в нем был только один элемент head, используйте take 1:

> take 1 [1..]
[1]

> take 1 []
[]

> take 1 $ find2 (> 4) [1..10]
[5]

> take 1 $ find2 (> 14) [1..10]
[]

Если вам нужно реализовать собственную функцию take 1, просто запишите ее уравнения в соответствии со всеми возможными входными данными:

take1 [] = []
take1 (x:xs) = [x]

или с filter,

findWithFilter p xs = take1 $ filter p xs

Ваше определение find1 не соответствует выводу, который вы показываете. Скорее следующее определение будет:

find1 e (x:xs) = if e x then [x]     -- you had `x`
                   else find1 e xs
find1 _ []     = []                  -- the missing clause

Обычно предикат p, а не e, называют мнемоническим устройством. Крайне желательно добавлять сигнатуры типов во все ваши определения верхнего уровня.

Если у вас возникли трудности с написанием этого самостоятельно, вы можете начать без подписи, а затем спросить GHCi, какой тип он сделал, чем использовать эту подпись , если она действительно выражает ваше намерение - иначе это означает, что вы ' мы кодировали что-то другое:

> :t find1
find1 :: (t -> Bool) -> [t] -> [t]

Это похоже на первую попытку.

За исключением того, что вы действительно предполагали, что в списке вывода никогда не будет более 1 элемента: это либо [], либо [x] для некоторых x, но не более одного.

Тип списка [] здесь слишком разрешительный, поэтому он не идеально подходит.

Такой тип все же существует. Он называется Maybe: значения типа Maybe t могут быть Nothing или Just x для некоторых x :: t (читай: x имеет тип t):

import Data.Maybe  (listToMaybe)

find22 p xs = listToMaybe $ filter p xs

Здесь нам даже не нужно было take 1: функция listToMaybe :: [a] -> Maybe a (читай: имеет тип функции с входом в [a] и выводом в Maybe a) уже берет не более одного элемента из своего ввода список, так как тип результата не допускает более одного элемента - в нем просто больше нет места. Таким образом, он правильно выражает наши намерения: создается не более одного элемента, если он есть:

> find22 (> 4) [1..10]
Just 5

> find22 (> 14) [1..10]
Nothing

Добавьте полную подпись над ее определением, когда вы уверены, что это то, что вам нужно:

find22 :: (a -> Bool) -> [a] -> Maybe a

Затем внедрите listToMaybe самостоятельно. Чтобы сделать это, просто следуйте типам и напишите уравнения, перечисляющие случаи возможного ввода, производя соответствующее значение типа вывода в каждом случае, как мы делали с take1 выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...