Можно ли написать функцию arity :: a -> Integer
для определения арности произвольных функций, такую, что
> arity map
2
> arity foldr
3
> arity id
1
> arity "hello"
0
?
Можно ли написать функцию arity :: a -> Integer
для определения арности произвольных функций, такую, что
> arity map
2
> arity foldr
3
> arity id
1
> arity "hello"
0
?
С OverlappingInstances
это просто:
{-# LANGUAGE FlexibleInstances, OverlappingInstances #-}
class Arity f where
arity :: f -> Int
instance Arity x where
arity _ = 0
instance Arity f => Arity ((->) a f) where
arity f = 1 + arity (f undefined)
Upd Обнаружена проблема. Вам нужно указать неполиморфный тип для полиморфных функций:
arity (foldr :: (a -> Int -> Int) -> Int -> [a] -> Int)
Пока не знаю, как это решить.
Upd2, как прокомментировал Sjoerd Visscher ниже, «вы должны указать неполиморфный тип, поскольку ответ зависит от того, какой тип вы выберете».
instance Arity x
более общий, чем instance Arity ((->) a f)
. Таким образом, без расширений GHC не может выбрать, какой из этих двух экземпляров использовать для функций. OverlappingInstances
указывает GHC, что а) такие случаи разрешены; б) ей нужно выбрать наиболее конкретный.
- person max taldykin; 03.12.2011
arity const
дает мне Ambiguous type variable 'a0' in the constraint: (Arity a0) arising from a use of 'arity'
- person Frank S. Thomas; 03.12.2011
arity (foldr :: (a -> (Int -> Int) -> Int -> Int) -> (Int -> Int) -> [a] -> Int -> Int)
- person Sjoerd Visscher; 03.12.2011
IncoherentInstances
LANGUAGE;)
- person is7s; 03.12.2011
arity foldr
производит 3
в ghci.
- person Dan Burton; 04.12.2011
IncoherentInstances
путается с лямбда-выражениями. arity $ \x y -> 3
производит 0
с непоследовательными экземплярами, 2
без них. Возможно, это та область, где IncoherentInstances
можно было бы улучшить?
- person Dan Burton; 04.12.2011
arity (\x y z -> (x,y,z)) is
3,
арность (\x y z -> x)` равно 0
, arity (\x y z -> (x,y)
равно 2
, а arity (\x y z -> (x,z))
неожиданно равно 1
. Здесь следует отметить, что если все переменные в левой части встречаются в правой части, то результат правильный, однако, если не все они встречаются в правой части, результат не имеет смысла. Нам нужен эксперт по GHC :D
- person is7s; 04.12.2011
IncoherentInstances
. По умолчанию путается. Например, arity (\x -> x)
дает 0. На самом деле это происходит всякий раз, когда лямбда не делает что-то полезное для параметра. Если вы делаете что-то полезное, например arity (\x -> x + 1)
, вы получаете 1. Если вы делаете что-то полезное с двумя параметрами (например, суммируете их), вы получаете 2. Я думаю, что это как-то связано с ленью, если параметр не используется в полезный способ, он не считает это арностью.
- person CMCDragonkai; 21.08.2015
Да, это можно сделать очень и очень легко:
arity :: (a -> b) -> Int
arity = const 1
Обоснование: если это функция, вы можете применить ее ровно к 1 аргументу. Обратите внимание, что синтаксис haskell делает невозможным применение к 0, 2 или более аргументам, поскольку f a b
на самом деле является (f a) b
, то есть не f applied to a and b
, а (f applied to a) applied to b
. Результатом, конечно, может быть другая функция, которую можно применить снова, и так далее.
Звучит глупо, но это не что иное, как правда.
a -> b -> c
это просто сахар для a -> (b -> c)
.
- person Dan Burton; 04.12.2011
Если id
имеет арность 1, разве id x
не должна иметь арность 0? Но, например, id map
идентично map
, у которого в вашем примере будет арность 2.
Имеют ли следующие функции одинаковую арность?
f1 = (+)
f2 = (\x y -> x + y)
f3 x y = x + y
Я думаю, что ваше понятие "арность" не совсем точно определено...
id x
имеет арность x
? Я имею в виду, это разумно, если вы посмотрите на id :: a -> a
.
- person Tarrasch; 03.12.2011
->
в типе функции, которые не заключены в круглые скобки. Таким образом, арность id x
зависит от x
.
- person Frank S. Thomas; 03.12.2011
()
.
- person fuz; 03.12.2011
В Haskell каждая «функция» принимает ровно один аргумент. То, что выглядит как «многоаргументная» функция, на самом деле является функцией, которая принимает один аргумент и возвращает другую функцию, которая принимает остальные аргументы. Так что в этом смысле все функции имеют арность 1.
Это невозможно со стандартным Haskell. Это может быть возможно с использованием IncoherentInstances или аналогичного расширения.
Но почему вы хотите это сделать? Вы не можете спросить у функции, сколько аргументов она ожидает, а затем использовать это знание, чтобы дать ей именно это количество аргументов. (Если вы не используете Template Haskell, в этом случае да, я ожидаю, что это возможно во время компиляции. Вы используете Template Haskell?)
Какую настоящую проблему вы пытаетесь решить?
*
.
- person CMCDragonkai; 21.08.2015
Как насчет этого:
arity :: a -> Int
arity (b->c) = 1 + arity (c)
arity _ = 0
Arity(F)
, который возвращает количество входовF
. Мне было любопытно, смогу ли я реализовать некоторые из функций, которые они определили в Haskell. - person Frank S. Thomas   schedule 23.09.2012