2012-03-03 2 views
1

Я читал ответ на этот вопрос: Haskell: difference between . (dot) and $ (dollar sign) И ответ поразил меня, как странно ... Что он имеет в виду + не имеет ввода? И затем я попробовал:Аргумент управляющей функции

((+) 1) 
((+) 1 1) 
((+) 1 1 1) 

Упс ... печальная новость. Но я уверен, что видел функции, которые могут казаться произвольным или очень большим количеством аргументов, чтобы полагать, что кто-то определил их способом a-> b-> c ...-> z. Должен быть какой-то способ справиться с этим! Я ищу что-то вроде & отдыха или & опционально в CL.

+2

Он не сказал, что '+' не принимает вход, но что '1 + 1' не принимает никаких данных. (То есть '1 + 1' не является функцией.) –

+1

Возможно, посмотрите на http://stackoverflow.com/questions/3467279/how-to-create-a-polyvariadic-haskell-function – phimuemue

+2

Возможны функции Variadic, но только с чрезмерным хакером типа (и, я считаю, расширением языка). Также обратите внимание, что ответ (я предполагаю, что вы имеете в виду принятый) не указывает, что '+' не имеет ввода - результат '1 + 1' не является функцией (не принимает никаких параметров). '+' - это обычная двоичная (как, например, взятие двух параметров), за исключением того, что вы должны записать ее как '(+)' для синтаксических соображений. – delnan

ответ

11

Конечно, вы можете определить VARIADIC дополнение функция, с некоторыми повозка, запряженная волами: класс типов

{-# LANGUAGE TypeFamilies #-} 

class Add r where 
    add' :: (Integer -> Integer) -> r 

instance Add Integer where 
    add' k = k 0 

instance (n ~ Integer, Add r) => Add (n -> r) where 
    add' k m = add' (\n -> k (m+n)) 

add :: (Add r) => r 
add = add' id 

И так:

GHCi> add 1 2 :: Integer 
3 
GHCi> add 1 2 3 :: Integer 
6 

Этот же трюк используется стандартным модулем Text.Printf. Обычно его избегают по двум причинам: один, типы, которые он дает вам, могут быть неудобными для работы, и вам часто приходится указывать явную подпись типа для вашего использования; два, это действительно взлом, и его следует использовать редко, если вообще. printf должен принимать любое количество аргументов и быть полиморфным, поэтому он не может просто взять список списка, но для добавления вы можете просто использовать sum.

Расширение языка не является строго необходимым здесь, но они делают использование проще (без них, вы должны явно указать тип каждого аргумента в примерах, которые я дал, например add (1 :: Integer) (2 :: Integer) :: Integer).

+0

Я не понимаю, почему требуется «FlexibleInstances». – is7s

+0

@ is7s: О, это не так; Я использовал его в предыдущей версии кода перед добавлением 'TypeFamilies'. Благодаря! – ehird

+0

@ehird Вы также не используете 'TypeFamilies'. – augustss

2

Это синтаксический компромисс: вы не можете (в общем) иметь как переменные функции arity, так и красивый синтаксис стиля Haskell для приложения-приложения одновременно. Это связано с тем, что многие выражения неоднозначны.

Предположим, у вас есть функция Foo, которая позволяет в Арность 1 или 2, и рассмотрим следующее выражение:

foo a b 

Если версия 1 или 2 аргумента обув использоваться здесь? Невозможно понять компилятор, так как это может быть версия с двумя аргументами, но в равной мере это может быть результат версии 1 аргумента, применяемой к b.

Следовательно, разработчикам языков необходимо сделать выбор.

  • Haskell выбирает хороший синтаксис функции приложения (не требуется Скобки)
  • Лисп выбирает для переменных функций Arity (и добавляет скобки для устранения неоднозначности)
+2

«... поскольку это может быть версия с двумя аргументами, но в равной мере это может быть результатом версии 1 аргумента, примененной к' b' ... », которая не будет иметь никакого значения: функции _all_ Haskell с« несколькими аргументами » на самом деле функции с одним аргументом возвращают функцию, которая принимает второй аргумент. Было бы двусмысленно то, должна ли функция возвращать такую ​​вторичную функцию, или конечный результат - двусмысленность, которое _can_, как показывает ehird, обрабатывается с помощью классов типов. – leftaroundabout

+0

Хорошо, мы обсуждаем гипотетический вариант Хаскелла с перегрузкой переменной arity, чтобы он мог сделать разницу - вот что означало бы перегрузка arity! Согласитесь, что трюк классов типов классный, но это не такой приятный интуитивный синтаксис - «:: Integer» - это что-то вроде взлома. – mikera

Смежные вопросы