Haskell: функция для определения арности функций? - PullRequest
21 голосов
/ 03 декабря 2011

Можно ли написать функцию arity :: a -> Integer для определения арности произвольных функций, например,

> arity map
2
> arity foldr
3
> arity id
1
> arity "hello"
0

?

Ответы [ 6 ]

25 голосов
/ 03 декабря 2011

Да, это можно сделать очень и очень легко:

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. Результатом, конечно, может быть другая функция, которую можно применить снова и т. Д.

Звучит глупо, но это не что иное, как правда.

18 голосов
/ 03 декабря 2011

Это просто с 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 ниже: «Вы должны указать неполиморфный тип, поскольку ответ зависит от того, какой тип вы выберете».

11 голосов
/ 03 декабря 2011

Если id имеет арность 1, не должно ли id x иметь арность 0?Но, например, id map идентичен map, который в вашем примере будет иметь арность 2.

Имеют ли следующие функции одинаковую арность?Понятие "арность" не вполне определено ...

3 голосов
/ 04 декабря 2011

В Haskell каждая «функция» принимает ровно один аргумент. То, что выглядит как функция с несколькими аргументами, на самом деле является функцией, которая принимает один аргумент и возвращает другую функцию, которая принимает остальные аргументы. Таким образом, в этом смысле все функции имеют арность 1.

2 голосов
/ 03 декабря 2011

Это невозможно со стандартным Haskell.Это может быть возможно с использованием IncoherentInstances или аналогичного расширения.

Но почему вы хотите это сделать?Вы не можете спросить функцию, сколько аргументов она ожидает, а затем использовать эти знания, чтобы дать ей именно то количество аргументов.(Если вы не используете Template Haskell, в этом случае, да, я ожидаю, что это возможно во время компиляции. Используете ли вы Template Haskell?)

Какую проблему вы решаете на самом деле?1005 *

1 голос
/ 05 декабря 2011

Как насчет этого:

arity :: a -> Int
arity (b->c) = 1 + arity (c)
arity _ = 0
...