给定一个至少带有n
参数的函数,我想旋转第一个参数,使其成为第n
个参数。例如(在无类型的lambda演算中):
r(λa. a) = λa. a
r(λa. λb. a b) = λb. λa. a b
r(λa. λb. λc. a b c) = λb. λc. λa. a b c
r(λa. λb. λc. λd. a b c d) = λb. λc. λd. λa. a b c d
等等。
可以用通用方式编写
r
吗?如果您知道n >= 2
怎么办?这是Scala中所述的问题:
trait E
case class Lam(i: E => E) extends E
case class Lit(i: Int) extends E
case class Ap(e: E, e: E) extends E
例如,旋转应采用
Lam(a => Lam(b => Lam(c => Ap(Ap(a, b), c))))
并返回Lam(b => Lam(c => Lam(a => Ap(Ap(a, b), c))))
。 最佳答案
技巧是标记所涉及函数的“最终”值,因为对于普通的haskell来说,a -> b
和a -> (b->c)
都只是单个变量的函数。
但是,如果这样做,我们可以做到。
{-# LANGUAGE TypeFamilies,FlexibleInstances,FlexibleContexts #-}
module Rotate where
data Result a = Result a
class Rotate f where
type After f
rotate :: f -> After f
instance Rotate (a -> Result b) where
type After (a -> Result b) = a -> Result b
rotate = id
instance Rotate (a -> c) => Rotate (a -> b -> c) where
type After (a -> b -> c) = b -> After (a -> c)
rotate = (rotate .) . flip
然后,查看其实际效果:
f0 :: Result a
f0 = Result undefined
f1 :: Int -> Result a
f1 = const f0
f2 :: Char -> Int -> Result a
f2 = const f1
f3 :: Float -> Char -> Int -> Result a
f3 = const f2
f1' :: Int -> Result a
f1' = rotate f1
f2' :: Int -> Char -> Result a
f2' = rotate f2
f3' :: Char -> Int -> Float -> Result a
f3' = rotate f3
关于scala - 将第一个参数旋转到函数成为第n个,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/5188212/