#haskell
#haskell
Вопрос:
Интересно, можно ли сделать обратную следующую функцию:
graphOf :: (Num a, Enum a) => (a -> b) -> [(a, b)]
graphOf f = [(e,v) | e <- [0..], v <- [f e]]
Я имею в виду, я не понимаю, как написать функцию Haskell
fromGraph :: (Enum a) => [(a, b)] -> (a -> b)
такое, что
fromGraph [(1,3),(2,4),(3,5)] :: (Num a) => a -> a
(fromGraph [(1,3),(2,4),(3,5)]) 1 == 3
(fromGraph [(1,3),(2,4),(3,5)]) 2 == 4
(fromGraph [(1,3),(2,4),(3,5)]) 3 == 5
Возможно ли это?
По крайней мере, для конечного списка входных данных?
Комментарии:
1. Да, это возможно.
2. Несвязанный:
[(e,v) | e <- [0..], v <- [f e]]
может быть упрощен до[(e,v) | e <- [0..], let v = f e]
или даже до[(e,f e) | e <- [0..]]
. Нет необходимости создавать одноэлементный список[f e]
только для того, чтобы иметь возможность извлекать из него (v <- ...
) .3. Вы можете зафиксировать ограничение, что график должен быть конечным, используя
Bounded
вместоEnum
в ограничениях.4. Смотрите Также Мой пакет юниверса ; он включает
Read
Show
экземпляры and для функций, которые включают идеи в этом Q / A , и различные другие экземпляры и операции, которые могут быть полезны в тех же ситуациях, когда вы хотелиgraphOf
бы иfromGraph
.
Ответ №1:
Самый простой способ — использовать lookup
функцию:
Prelude> :m Data.List
Prelude Data.List> lookup 1 [(1,3),(2,4),(3,5)]
Just 3
Prelude Data.List> lookup 2 [(1,3),(2,4),(3,5)]
Just 4
Prelude Data.List> lookup 3 [(1,3),(2,4),(3,5)]
Just 5
Хотя это довольно неэффективно (для каждого запроса он просто проходит по списку линейно). Возможно, вы захотите подкрепить ее более быстрым механизмом поиска, используя структуры из containers
unordered-containers
пакетов or, например
import qualified Data.HashMap.Strict as HMS
import Data.Hashable (Hashable)
fastLookup :: Hashable k => [(k,b)] -> k -> Maybe b
fastLookup l = k -> HMS.lookup k table
where table = HMS.fromList l
Обратите внимание, что я написал fastLookup l = k -> ...
. Не упрощайте это fastLookup l k = ...
, потому что это приведет к повторному построению хэш-карты для каждого запроса.
Ответ №2:
Вы могли бы написать что-то вроде этого
fromGraph :: [(Int, b)] -> Int -> b
fromGraph g i = snd (g !! i)
Это будет работать только для Int
индексов, а также предполагает, что для каждого i
элемента в графе g
at g !! i
i
также будет иметь индекс. Если вы хотите сделать это немного более обобщенно, вы могли бы написать это:
fromGraph :: Eq a => [(a, b)] -> a -> b
fromGraph g i = snd $ head $ filter ((==i) . fst) g
Не то, чтобы это все равно выдавало ошибку, если вы попытаетесь использовать эту функцию с индексом, который не является частью графика.
Комментарии:
1. В этом случае, я думаю, что понимание списка также является вполне читаемой альтернативой
filter
:fromGraph g i = head [b | (a, b) <- g, a == i]
.