接受函数或值的Haskell函数,然后调用函数或返回值

sea*_*lor 2 haskell functional-programming

如何在Haskell中编写一个类型声明和函数,它接受一个函数(它本身不带参数)或一个值.给定一个函数时,它调用该函数.给定值时,它返回值.

[编辑]为了给出更多的上下文,我很好奇如何在Haskell中解决这个问题而不需要喋喋不休:设计函数f(f(n))== -n

肖恩

Aad*_*hah 5

我很好奇如何在Haskell中解决这个问题,而不是苦恼:设计函数f(f(n))== -n

这实际上很容易解决:

when :: (a -> Bool) -> (a -> a) -> a -> a
when p f x = if p x then f x else x

f :: Integer -> Integer
f = (+) <$> when even negate <*> signum
Run Code Online (Sandbox Code Playgroud)

我们如何推导出这个?考虑:

f (f n) = (-n) -- (0) - from the interview question

f x     = y    -- (1) - assumption

f y     = (-x) -- (2) - from (0) and (1), f (f x) = (-x)

f (-x)  = (-y) -- (3) - from (0) and (2), f (f y) = (-y)

f (-y)  = x    -- (4) - from (0) and (3), f (f (-x)) = x
Run Code Online (Sandbox Code Playgroud)

现在,如果您看到这些方程式的左侧,那么您会注意到有四种情况:

  1. f x.
  2. f y.
  3. f (-x).
  4. f (-y).

请注意,函数的域f分为正数和负数,x和(-x),y和(-y).让我们假设,x并y共同构成了一套正数和(-x)与(-y)共同构成了一套负数.

正数集合分为两个正确的 不相交子集,x和y.我们如何将正数集合分成两个正确的不相交子集?奇数和偶数是一个很好的候选人.因此,我们假设这x是一组正奇数,并且y是正偶数集.

使用奇数和偶数的另一个优点是,当否定奇数时,奇数仍为奇数,偶数仍为偶数.因此,(-x)是负奇数(-y)的集合并且是负偶数集合.

现在,再考虑四个案例.请注意,只有当数字为偶数时,符号才会更改:

  1. f x = y (标志不会改变).
  2. f y = (-x) (签署变更).
  3. f (-x) = (-y) (标志不会改变).
  4. f (-y) = x (签署变更).

因此,我们只在偶数(即when even negate)时否定数字.

接下来,我们需要将奇数转换为偶数,反之亦然.最简单的方法是在数字中加或减一个.但是,应注意产生的数字不是0.考虑以下特例0:

f 0    = z    -- (a) - assumption

f z    = (-0) -- (b) - from (0) and (a), f (f 0) = (-0)

f (-0) = (-z) -- (c) - from (0) and (b), f (f z) = (-z)

(-0)   = 0    -- (d) - reflexivity

f (-0) = f 0  -- (e) - from (d)

(-z)   = z    -- (f) - from (a) and (c) and (e)

z      = 0    -- (g) - from (d) and (f)

f 0    = 0    -- (h) - from (a) and (g)
Run Code Online (Sandbox Code Playgroud)

因此,f n = 0 当且仅当 n = 0.因此,让我们考虑的邻居0,1和(-1).它们都是奇数.因此,它们不会被否定.但是,它们确实需要转换为偶数(除了0).因此,1被转换成2并被(-1)转换成(-2).

因此,对于奇数,我们只需将数字的符号添加到数字本身.

现在,考虑偶数.我们知道:

f 1    = 2    -- (A)

f (-1) = (-2) -- (B)
Run Code Online (Sandbox Code Playgroud)

因此:

f 2    = (-1) -- (C), from (0) and (A), f (f 1) = (-1)

f (-2) = 1    -- (D), from (0) and (B), f (f (-1)) = 1
Run Code Online (Sandbox Code Playgroud)

我们知道偶数也总是被否定了.因此,2首先成为(-2),反之亦然.让原始偶数为n.因此,首先我们negate n再加signum n上它:

evenF n    = negate n    + signum n

evenF 2    = negate 2    + signum 2
           = (-2)        + 1
           = (-1)

evenF (-2) = negate (-2) + signum (-2)
           = 2           + (-1)
           = 1

evenF 0    = negate 0    + signum 0
           = 0           + 0
           = 0
Run Code Online (Sandbox Code Playgroud)

因此,对于奇数情况和偶数情况,我们将原始数字的符号添加到when even negate.因此,f定义为:

f :: Integer -> Integer
f = (+) <$> when even negate <*> signum
Run Code Online (Sandbox Code Playgroud)

希望有所帮助.