Можно ли в Haskell реализовать функцию, которая возвращает собственное имя функции?
Возможный тип может быть (a -> b) -> String
.
Можно ли в Haskell реализовать функцию, которая возвращает собственное имя функции?
Возможный тип может быть (a -> b) -> String
.
Вам нужна функция, которая принимает аргумент функции и возвращает имя переменной сайта определения, которое соответствует имени этой функции?
Это невозможно без метапрограммирования, которое обычно является признаком того, что вы делаете что-то не так :). Но если предположить, что это не так, один из способов добиться чего-то в правильном направлении — использовать Template Haskell, который может получить в уникальных именах (как компилятор называет вещи). Например.
Prelude Language.Haskell.TH> :set -XTemplateHaskell
Prelude Language.Haskell.TH> let f x y = x + y
Prelude Language.Haskell.TH> $( stringE . show =<< reify 'f )
"VarI f_1627394057
(ForallT [PlainTV a_1627394063]
[ClassP GHC.Num.Num [VarT a_1627394063]]
(AppT (AppT ArrowT (VarT a_1627394063))
(AppT (AppT ArrowT (VarT a_1627394063))
(VarT a_1627394063))))
Nothing (Fixity 9 InfixL)"
И теперь мы многое знаем о переменной. Таким образом, вы можете играть в игры, передавая имя функции (через 'f), а не сам f.
Вы, безусловно, находитесь в мире размышлений и метапрограммирования, поэтому было бы полезно узнать больше о том, что вы пытаетесь сделать.
Чтобы уточнить что-то, упомянутое в посте Дона: в Haskell нет функций с именами. Существуют привязки, которые могут связывать функции, но если бы у меня была такая функция (назовите ее getName
), которую вы ищете, то что бы вы ожидали, что она вернется:
let f x = x
g = f
h = f
in getName g == getName h
Я не знаю, для чего вам это нужно, но, может быть, достаточно упрощенного решения? Вот так:
data NamedFunction a b = NamedFunction {
name :: String,
apply :: a -> b
}
timesTwo :: NamedFunction Int Int
timesTwo = NamedFunction "timesTwo" (\x -> 2 * x)
который вы можете использовать следующим образом:
ghci> timesTwo `apply` 7
14
ghci> name timesTwo
"timesTwo"
Затем вы можете написать свою собственную версию (.)
:
-- contrast (.) :: (b -> c) -> (a -> b) -> (a -> c)
compose :: NamedFunction b c -> NamedFunction a b -> NamedFunction a c
compose (NamedFunction n1 f1) (NamedFunction n2 f2) =
NamedFunction (n1++ " . " ++ n2) (f1 . f2)
В ГКИ:
ghci> let f = timesTwo `compose` timesTwo in (f `apply` 7, name f)
(28,"timesTwo . timesTwo")
Вам придется заново реализовать свои собственные версии map
, filter
и так далее, и позже вы обязательно столкнетесь с другими проблемами, но, возможно, это все, что вам нужно...
Я что-то пропустил? Эта функция возвращает собственное имя функции.
Prelude> let myNameIs::(a->b) -> String; myNameIs f = "myNameIs"
Prelude> :type myNameIs
myNameIs :: (a -> b) -> String
Prelude> myNameIs myNameIs
"myNameIs"
Вы можете предварительно обработать исходный код с помощью CPP. В СРР
#define _NAMEOF(name) #name
определяет макрос _NAMEOF
для преобразования текста в строки (включая окружение его программистскими кавычками). Затем вы можете использовать его следующим образом:
head [] = error $ _NAMEOF(head) ++ ": empty list!"
который CPP должен переводиться в действительную строку исходного кода Haskell:
head [] = error $ "head" ++ ": empty list!"
(a -> b) -> String
не может проверить свой аргумент (кромеseq
его обработки или применения его снизу) из-за своего полиморфного типа. Таким образом, у него нет средств для идентификации своего аргумента. - person Daniel Fischer   schedule 07.03.2013() -> String
(и реализация довольно тривиальна)? - person sepp2k   schedule 07.03.2013let f = id in findName f
предположительно будет предназначено для производства"f"
, ноfindName id
предположительно будет предназначено для производства"id"
. Это все связано с тем, что у функций просто нет имен; переменные могут быть в области видимости, которая имеет тип функции, но это все. - person Antal Spector-Zabusky   schedule 08.03.2013