Как мне создать функции Haskell, которые возвращают функции? - PullRequest
1 голос
/ 17 марта 2012

Я хотел бы создать три функции на Haskell: a, b и c.

Каждая функция должна иметь один аргумент. Аргумент является одной из трех функций.

Я бы хотел, чтобы функция a имела такое поведение:

  • если аргумент является функцией a, тогда вернуть функцию a.
  • если аргумент является функцией b, вернуть функцию b.
  • если аргумент является функцией c, вернуть функцию a.

Вот краткий обзор поведения, которое я желаю для функции a:

a a = a
a b = c
a c = a 

А вот поведение, которое я желаю для двух других функций:

b a = a
b b = a
b c = c

c a = c
c b = b
c c = c

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

  a (c b)
= a (b)
= c

Как мне создать эти функции?

Ответы [ 4 ]

16 голосов
/ 17 марта 2012

Поскольку вы не указали никаких критериев того, как вы собираетесь наблюдать результаты, то a = b = c = id удовлетворяет вашим критериям. Но, конечно, это не то, что вы хотите. Но идея важна: не только важно, какое поведение вы хотите, чтобы ваши функции имели, но и как вы будете наблюдать это поведение.

Существует наиболее общая модель, если вы допускаете некоторую свободу в обозначениях, и вы получаете это, используя алгебраический тип данных:

data F = A | B | C
    deriving (Eq, Show) -- ability to compare for equality and print

infixl 1 % 
(%) :: F -> F -> F
A % A = A
A % B = C
A % C = A
B % A = A
...

и так далее. Вместо того, чтобы говорить a b, вы должны сказать A % B, но это единственное отличие. Вы можете составить их:

  A % (C % B)
= A % B
= B

и вы можете превратить их в функции, частично применив (%):

a :: F -> F
a = (A %)

Но вы не можете сравнить это a, как говорит Эхирд. Эта модель эквивалентна той, которую вы указали, она выглядит немного иначе.

11 голосов
/ 17 марта 2012

Это невозможно;вы не можете сравнивать функции друг с другом, поэтому нет способа проверить, является ли ваш аргумент a, b, c или чем-то еще.

Действительно, для Haskell было бы невозможнодавайте проверим, одинаковы ли две функции: поскольку Haskell является ссылочно прозрачным, замена двух разных реализаций одной и той же функции не должна иметь никакого эффекта.То есть, до тех пор, пока вы даете один и тот же вход для каждого выхода, точная реализация функции не должна иметь значения, и хотя доказать, что \x -> x+x и \x -> x*2 - это одна и та же функция, легко, это неразрешимо вgeneral .

Кроме того, нет никакого возможного типа, который a мог бы иметь, если бы он принимал себя в качестве аргумента (конечно, id id типов, но id может принимать что угодно в качестве первого аргумента - это означает, что он не может исследовать это так, как вы хотите).

Если вы пытаетесь достичь чего-то с этим (вместо того, чтобы просто играть с ним из любопытства -это нормально, конечно), тогда вам придется сделать это другим способом.Трудно сказать, каким именно образом это было бы без конкретных деталей.

4 голосов
/ 17 марта 2012

Ну, вы можете сделать это так:

{-# LANGUAGE MagicHash #-}

import GHC.Prim
import Unsafe.Coerce

Эта функция из ответа ehird здесь :

equal :: a -> a -> Bool
equal x y = x `seq` y `seq`
              case reallyUnsafePtrEquality# x y of
                 1# -> True
                 _  -> False

Теперь перейдем к делу.Заметьте, что вам нужно принудительно привести аргументы и возвращаемые значения, так как нет никакого возможного типа, который эти функции действительно могут иметь, как указало ehird.

a,b,c :: x -> y
a x | unsafeCoerce x `equal` a = unsafeCoerce a
    | unsafeCoerce x `equal` b = unsafeCoerce c
    | unsafeCoerce x `equal` c = unsafeCoerce a

b x | unsafeCoerce x `equal` a = unsafeCoerce a
    | unsafeCoerce x `equal` b = unsafeCoerce a
    | unsafeCoerce x `equal` c = unsafeCoerce c

c x | unsafeCoerce x `equal` a = unsafeCoerce c
    | unsafeCoerce x `equal` b = unsafeCoerce b
    | unsafeCoerce x `equal` c = unsafeCoerce c

Наконец, некоторые тесты:

test  = a (c b) `equal` c   -- Evaluates to True
test' = a (c b) `equal` a   -- Evaluates to False

Эхх ...

0 голосов
/ 17 марта 2012

Как уже отмечалось, функции нельзя сравнивать на равенство. Если вы просто хотите, чтобы функции, удовлетворяющие алгебраическим законам в вашей спецификации, сделали их равными функции тождественности, все будет хорошо.

Надеюсь, вы знаете, что если вы отправите вопрос, связанный с домашней работой, в Stack Overflow, сообщество ожидает, что вы определите его как таковой.

...