Squeak.ru - шаблоны программирования

Выберите конкретное изображение из списка

У меня есть следующая функция:

blockToPicture :: Int -> [Picture] -> Picture
blockToPicture n [pic1,pic2,pic3] | n==0 = ...
                                  | n==1 = ...
                                  | otherwise = ...

Если n==0 я хочу выбрать pic1, если n==1 я хочу выбрать pic2. В противном случае я хочу выбрать pic3. Проблема в том, что одна из картинок не загружается, поэтому ее нет в списке. Вместо [pic1,pic2,pic3] у меня что-то вроде [Pic1,Pic3]. Когда функция supposed выбирает изображение, которого нет в списке, я хочу, чтобы вместо него было написано "X". Вместо этого я буду использовать функцию text "X". Проблема в том, что я не знаю, как заставить его писать "X" вместо выбора неправильного изображения.

Изменить: я создал следующую функцию, но по какой-то причине я получаю сообщение об ошибке «Переменная не в области действия» для изображений.

blocoParaPicture :: Int -> [Picture] -> Picture
blocoParaPicture b l | b==0 = if elem pic1 l then pic1 else text "X"
                     | b==1 = if elem pic2 l then pic2 else text "X"
                     | otherwise = if elem pic3 l then pic3 else text "X"

  • Ну, здесь вы можете снова сопоставить шаблоны в списках, таких как [pic1, pic2], [pic1] и [], и каждый раз заменять случаи, которые больше не охватываются. Но я предлагаю вам реализовать рекурсивный шаблон, в котором вы рекурсивно работаете с уменьшенным индексом и хвостом списка. 08.12.2018
  • Нет, нет, нет, тогда вам следует использовать список типа [Maybe Picture]. 08.12.2018
  • Что делает функция текста «X»? вместо этого можно использовать (любая строка изображения). 08.12.2018

Ответы:


1

Вы не можете просто удалить изображение, которое не загружается; если вы попытались загрузить 3 изображения и получили [some_pic, some_other_pic], как узнать, какое из них не загрузилось? Вам нужен список типа [Maybe Picture], где Just pic соответствует успешно загруженному изображению, а Nothing — сбою. Тогда ваша функция будет выглядеть

blockToPicture :: Int -> [Maybe Picture] -> Maybe Picture
blockToPicture _ []          = Nothing                  -- No pictures to choose from
blockToPicture 0 (Nothing:_) = Nothing                  -- Desired picture failed to load
blockToPicutre 0 (x:_)       = x                        -- Found desired picture!
blockToPicture n (_:xs)      = blockToPicture (n-1) xs  -- This isn't it; try the next one

Адаптация предложения Хорхе Адриано по использованию lookup (это хорошо)

import Control.Monad

blockToPicture :: Int -> [Maybe Picture] -> Maybe Picture
blockToPicture n pics = join (lookup n (zip [0..] pics))

Поскольку lookup :: a -> [(a,b)] -> Maybe b и b здесь равно Maybe Picture, у нас есть сценарий, в котором lookup возвращает Nothing, если n слишком велико; Just Nothing, если нужное изображение не загружается, и Just (Just pic), если нужное изображение найдено. Функция join из Control.Monad уменьшает значение Maybe (Maybe Picture), которое возвращает lookup, до «обычного» Maybe Picture, которое нам нужно.

08.12.2018

2
blocoParaPicture :: Int -> [Picture] -> Picture
blocoParaPicture b l | b==0 = if elem pic1 l then pic1 else text "X"
                     | b==1 = if elem pic2 l then pic2 else text "X"
                     | otherwise = if elem pic3 l then pic3 else text "X"

Я получаю сообщение об ошибке Переменная не соответствует изображениям.

Выражение elem x xs проверяет, находится ли данное x в списке xs. В вашем коде, когда вы пишете pic1, в области видимости такой переменной нет, она нигде не определена. В любом случае вы не хотите искать конкретное значение в списке, а хотите знать, существует ли данная позиция, то есть достаточно ли длинный список.

Также вы не можете просто писать внутри функции с этим типом. В Haskell ввод и вывод отражается на типах. Это чистая функция, которая принимает некоторые аргументы и вычисляет результат, без побочных эффектов.

Итак, что вы можете сделать здесь, это вернуть Maybe Picture, который имеет значения Nothing или Just pic в зависимости от того, можете ли вы вернуть изображение или нет. Или вы можете использовать Either String Picture, где значения имеют форму Left string или Right pic. Давайте рассмотрим этот последний вариант.

blocoParaPicture :: Int -> [Picture] -> Either String Picture

С точки зрения реализации мы могли бы отклониться от темы, чтобы перейти к обсуждению управления ошибками (поскольку проблема в том, что доступ к позиции может не получиться). Но на данный момент я думаю, что лучше избегать этого обходного пути, так что давайте будем (относительно) простыми.

прямая рекурсия (самая простая)

Самым простым и прямым методом будет прямая рекурсия (как предложено @chepner в комментариях ниже).

blocoParaPicture :: Int -> [Picture] -> Either String Picture
blocoParaPicture _ []     = Left "X"
blocoParaPicture 0 (x:_)  = Right x
blocoParaPicture n (x:xs) = safe (n-1) xs

убедиться, что !! выполнено успешно

Если вы хотите использовать стандартную функцию доступа !!, один из способов сделать это (но потенциально неэффективный в общем случае) — создать безопасный бесконечный список.

import Data.List 

blocoParaPicture :: Int -> [Picture] -> Either String Picture
blocoParaPicture n xs = zs !! n 
                        where zs = [Right x | x <- xs] ++ repeat (Left "X")

Список zs — это бесконечный список, состоящий из двух списков. Сначала [Right x | x <- xs], как и в исходном списке, но каждый элемент x становится Right x. Затем и далее все элементы имеют форму Left "X" для обозначения отказа. В целом описанный выше подход может быть неэффективным. Если вы ищете большое n в списке:

[Right 1, Right 2] ++ [Left "X", Left "X", ...

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

используя lookup

Еще одна возможность, похожая на вашу попытку использовать функцию elem, заключается в использовании lookup для индексов. Эта функция безопасна по своей конструкции.

lookup :: Eq a => a -> [(a, b)] -> Maybe b

Следуя этому подходу, вы сначала создаете список,

[(0,x0), (1,x1), (2,x2) ...(k,xk)]

а затем найдите заданный вами n, чтобы вернуть связанный xn (или Nothing).

blocoParaPicture' :: Int -> [Picture] -> Maybe Picture
blocoParaPicture' n xs = lookup n (zip [1..] xs)

Это возвращает Nothing, если он не найден. Но при желании вы можете конвертировать в Either через maybe :: b -> (a -> b) -> Maybe a -> b.

blocoParaPicture :: Int -> [Picture] -> Either String Picture
blocoParaPicture n xs = maybe (Left "X") Right (lookup n (zip [1..] xs))

Это, конечно, слишком сложно, когда все, что вам нужно, это простая функция доступа. Но может быть удобно в ситуациях, когда все не так просто.

08.12.2018
  • В патологическом случае, когда n намного больше, чем length xs, было бы эффективнее просто проверить n > length xs, чем перебирать достаточно большую часть бесконечного списка. 08.12.2018
  • Или просто напишите рекурсию напрямую вместо использования !!: bPP _ [] = Left "X"; bPP 0 (x:_) = Right x; bPP n (x:xs) = bPP (n-1) xs. 08.12.2018
  • Действительно, вы правы, я обдумал это. В любом случае, он новичок и якобы смотрит на список всего из 3 элементов... каждый подход его чему-то учит. 08.12.2018
  • Добавил ваше предложение, возможно, это лучше всего. Попытка придерживаться !! могла сделать его излишне сложным. Я также искал безопасную альтернативу !! раньше, но нашел только Data.List.Safe, но она использует то же имя, что и стандартные функции, и здесь это может сбить с толку. 08.12.2018
  • Новые материалы

    Угловая структура архитектуры
    Обратите внимание, что эта статья устарела, я решил создать новую с лучшей структурой и с учетом автономных компонентов: https://medium.com/@marekpanti/angular-standalone-architecture-b645edd0d54a..

    «Данные, которые большинство людей используют для обучения своих моделей искусственного интеллекта, поставляются со встроенным…
    Первоначально опубликовано HalkTalks: https://hacktown.com.br/blog/blog/os-dados-que-a-maioria-das-pessoas-usa-para-treinar-seus-modelos-de-inteligencia-artificial- ja-vem-com-um-vies-embutido/..

    Сильный ИИ против слабого ИИ: различия парадигм искусственного интеллекта
    В последние годы изучению и развитию искусственного интеллекта (ИИ) уделяется большое внимание и прогресс. Сильный ИИ и Слабый ИИ — две основные парадигмы в области искусственного интеллекта...

    Правильный способ добавить Firebase в ваш проект React с помощью React Hooks
    React + Firebase - это мощная комбинация для быстрого и безопасного создания приложений, от проверки концепции до массового производства. Раньше (знаете, несколько месяцев назад) добавление..

    Создайте API с помощью Python FastAPI
    Создание API с помощью Python становится очень простым при использовании пакета FastAPI. После установки и импорта вы можете создать приложение FastAPI и указать несколько конечных точек. Каждой..

    Веселье с прокси-сервером JavaScript
    Прокси-серверы JavaScript — это чистый сахар, если вы хотите создать некоторую общую логику в своих приложениях, чтобы облегчить себе жизнь. Вот один пример: Связь клиент-сервер Мы..

    Получить бесплатный хостинг для разработчиков | Разместите свой сайт за несколько шагов 🔥
    Статические веб-сайты — это веб-страницы с фиксированным содержанием и его постоянным содержанием. Но теперь статические сайты также обрабатывают динамические данные с помощью API и запросов...