Haskell: функция для определения арности функций?

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

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

?

6 ответов

Решение

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

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

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

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

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

У следующих функций одинаковая арность?

f1 = (+)
f2 = (\x y -> x + y)
f3 x y = x + y

Я думаю, что ваше понятие "arity" не очень хорошо определено...

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

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

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

Какова ваша настоящая проблема, которую вы пытаетесь решить?

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

arity :: a -> Int
arity (b->c) = 1 + arity (c)
arity _ = 0
Другие вопросы по тегам