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