Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 此函数是否可以用无点样式编写?若否,原因为何?_Haskell_Pointfree - Fatal编程技术网

Haskell 此函数是否可以用无点样式编写?若否,原因为何?

Haskell 此函数是否可以用无点样式编写?若否,原因为何?,haskell,pointfree,Haskell,Pointfree,一个相关的问题是,但是一些答案说几乎任何东西都可以无点生成,那么这个函数有什么错呢 \[x]->x 似乎不能用无点的方式写。这是否意味着它不能这样写?如果是,理论原因是什么 我只能观察到上面的函数是head(或last,fwiw)的“残废”版本,它只能对单例列表进行操作。实际上,应用于非单例列表时,它会以这种方式在ghci中出错: ***异常::380:5-13:lambda中的非穷举模式 也许模式上的“非穷尽性”是某些函数不能以无点风格编写的原因 根据答案进行编辑: 我没想到我的问题的答案

一个相关的问题是,但是一些答案说几乎任何东西都可以无点生成,那么这个函数有什么错呢

\[x]->x
似乎不能用无点的方式写。这是否意味着它不能这样写?如果是,理论原因是什么

我只能观察到上面的函数是
head
(或
last
,fwiw)的“残废”版本,它只能对单例列表进行操作。实际上,应用于非单例列表时,它会以这种方式在ghci中出错:

***异常::380:5-13:lambda中的非穷举模式
也许模式上的“非穷尽性”是某些函数不能以无点风格编写的原因

根据答案进行编辑:


我没想到我的问题的答案会如此复杂(我觉得我只是认为简短的答案是否定的,事实上它不能),所以我需要找一些时间仔细阅读它们,进行一些实验,并围绕它们进行思考,否则我无法决定哪一个应该被接受。目前,Jon Purdy的答案是+1,我可以很容易地理解到这一点,这是我在普通代码中要停下来的地方。

嗯,数据类型不是函数。只要您的函数没有展开任何数据值(即,它只是在函数/构造函数之间洗牌),您就可以无点编写它,但没有无点匹配的语法。但是,每个数据类型只需要一个非点自由函数:fold。在Haskell中,数据类型基本上是由它们的折叠定义的。将相关数据类型的折叠作为原语,您可以无需重写任何函数点。请注意,实际上有几个可能的“褶皱”。对于
[a]
,递归的(来自Church/Böhm Berardocci编码)是
foldr::(a->B->B)->B->[a]->B
。另一个可能的折叠是“
case
-但它是一个函数”之一,
(a->[a]->b)->b->[a]->b
,它来自Scott编码(递归可以用另一个“有点无点原语”修复),但是,正如@SilvioMayolo所指出的,在标准库中没有这样的函数。两者都可以,但我们没有预定义后者,所以我们只使用
foldr

\[x] -> x
可以写

fst . foldr (\x f -> (snd f x, \_ -> error "got (_ : _ : _) wanted [x]")) (error "got [] wanted [x]", id)
-- I don't care enough to replicate the exact exceptions.
-- this is "flattened" from
let fold [] = (error "got [] wanted [x]", id)
    fold (x : xs) = (snd (fold xs) x, \_ -> error "got (_ : _ : _) wanted [x]")
in  fst . fold
fold
返回一对,基本上是
(如果这是整个列表,返回什么,如果不是,如何变换头部)
。对于
[]
,如果这是整个列表,我们希望返回一个错误,但是在点击
[]
之前通过元素。对于
x:xs
,如果前面有一个元素,我们希望忽略它并返回一个错误,如果没有,我们希望将它传递给
snd(fold xs)
,它检查
xs=[]
或是否给出错误。我们已经消除了所有匹配项,因此只需将其通过pointfree.io,即可将参数中的
\x f->\ucode>输出到
foldr

behead = fst . foldr (flip flip (const (error "got (_ : _ : _) wanted [x]")) . ((,) .) . flip snd) (error "got [] wanted [x]", id)
ghci> :t behead
behead :: Foldable t => t c -> c
ghci> behead []
*** Exception: got [] wanted [x]
ghci> behead [1]
1
ghci> behead [1, 2]
*** Exception: got (_ : _ : _) wanted [x]
ghci> behead [1..]
*** Exception: got (_ : _ : _) wanted [x]
可爱

注意:这个答案的前一个版本使用了“内联”辅助数据类型,基本上是因为它只是在我写它的时候“出现在我面前”。但是,它无法正确处理无限列表(
斩首[1..]
将挂起)。这个版本使用内置的pairs作为辅助数据类型,它有足够的库支持,我不需要内联它们就可以使它成为无点的。内联
(,)
稍微困难一些,从而消除了
fst
snd
实现中的点完整性,但使用这种新类型仍然是可能的:

newtype Pair a b = Pair { unPair :: forall r. (a -> b -> r) -> r }
或者,对类型进行一些欺骗,并使用以下方法:

-- residual pointfullness can be reduced by pointfree.io
\xs -> foldr (\x r f -> f (r (const id) x) (\_ -> error "got (_ : _ : _) wanted [x]")) (\f -> f (error "got [] wanted [x]") id) xs (\x _ _ -> x) undefined

当然,几乎任何事情都可以毫无意义。棘手的问题是在结果表达式中允许哪些函数。如果我们进行模式匹配,通常需要一个fold函数来进行匹配。因此,例如,如果我们在一个
上匹配模式,可能是一个
,我们需要将其替换为。类似地,
模式可以根据编写

注意签名中的模式

data Maybe a = Nothing | Just a

maybe :: b -> (a -> b) -> (Maybe a -> b)
可能a
有两个构造函数,一个不带参数,另一个带
a
。因此,
maybe
接受两个参数:一个是0元函数(
b
),另一个接受
a
a->b
),然后从
maybe a->b
返回一个函数。相同的模式出现在

data Either a b = Left a | Right b

either :: (a -> c) -> (b -> c) -> (Either a b -> c)
两个案例。第一种方法采用
a
并生成我们想要的
c
。第二个接受a
b
并生成我们想要的任何
c
。在每种情况下,我们都希望sum类型中的每个可能项都有一个函数

为了系统地释放像
\[x]->x这样的函数,我们需要类似的折叠<代码>[a]
基本上被声明为

data [a] = [] | a : [a]
所以我们需要一个有这个签名的函数

list :: b -> (a -> [a] -> b) -> ([a] -> b)
现在,
flip foldr
快到了

flip foldr :: b -> (a -> b -> b) -> ([a] -> b)
但它是递归的。它在
a:[a]
[a]
部分调用其提供的函数。我们需要一个真正的折叠,这不是Haskell的基本库提供的。快速的Hoogle搜索告诉我们这个函数确实存在于一个名为的包中。当然,对于这个小例子,我们可以很容易地自己编写

list :: b -> (a -> [a] -> b) -> ([a] -> b)
list f g x = case x of
               [] -> f
               (y:ys) -> g y ys
现在我们可以轻松地将其应用于您的
\[x]->x
。首先,让我们编写函数的实际功能,包括所有混乱的
未定义的
情况(为了简洁起见,我将使用
未定义的
,而不是一条很长的错误消息)

现在,每个case语句只与每个构造函数匹配一次。这是一个成熟的转变成褶皱

func :: [a] -> a
func x = case x of
         [] -> undefined
         (y:ys) -> list y undefined ys
现在我们也转换了外壳

func :: [a] -> a
func x = list undefined (\y -> list y undefined) x
所以我们有

func :: [a] -> a
func = list undefined (\y -> list y undefined)
或者,如果我们想成为tr
func :: [a] -> a
func = list undefined (\y -> list y undefined)
func :: [a] -> a
func = list undefined (flip list undefined)
func' :: [a] -> a
func' = foldr1 (const (const undefined))
fromSingleton :: (Foldable t) => t a -> a
fromSingleton
  = fromMaybe (error "empty list")
  . foldr (flip maybe (error "plural list") . Just) Nothing
type Maybe' r a
  = r          -- ‘Nothing’ continuation
  -> (a -> r)  -- ‘Just’ continuation
  -> r         -- Result

just' :: a -> Maybe' r a
-- just' = \ x _n j -> j x
just'
  = const     -- Ignore ‘Nothing’ continuation
  . flip ($)  -- Apply ‘Just’ continuation to value

nothing' :: Maybe' r a
-- nothing' = \ n _j -> n
nothing' = const  -- Ignore ‘Just’ continuation

maybe' :: r -> (a -> r) -> Maybe' r a -> r
-- maybe' = \ n j k -> k n j
maybe'
  = flip      -- Apply to ‘Just’ continuation
  . flip ($)  -- Apply to ‘Nothing’ continuation

fromMaybe' :: r -> Maybe' r r -> r
-- fromMaybe' = \ n k -> k n id
fromMaybe' = flip maybe' id  -- Pass ‘id’ as ‘Just’ continuation
> :t fromMaybe' (error "empty list") . foldr (flip maybe' (error "plural list") . just') nothing'

<interactive>:…:…: error:
    • Occurs check: cannot construct the infinite type: c ~ Maybe' c c
      Expected type: c -> Maybe' c c -> Maybe' c c
        Actual type: c -> Maybe' (Maybe' c c) c -> Maybe' c c
    • In the first argument of ‘foldr’, namely
        ‘(flip maybe' (error "plural list") . just')’
      In the second argument of ‘(.)’, namely
        ‘foldr (flip maybe' (error "plural list") . just') nothing'’
      In the expression:
        fromMaybe' (error "empty list")
          . foldr (flip maybe' (error "plural list") . just') nothing'
> :t fromMaybe' (error "empty list") . foldr (\ x acc -> \ n j -> maybe' (just' x n j) (error "plural list") acc) nothing'

fromMaybe' (error "empty list") . foldr (\ x acc -> \ n j -> maybe' (just' x n j) (error "plural list") acc) nothing'
  :: Foldable t => t c -> c
fromSingleton
  = fromMaybe' (error "empty list")
  . foldr
    (\ x acc
      -> \ n j
        -> maybe'
          (just' x n j)
          (error "plural list")
          acc)
    nothing'

-- Move ‘n’ & ‘j’ past ‘error …’ with ‘flip’:

fromSingleton
  = fromMaybe' (error "empty list")
  . foldr
    (\ x acc
      -> \ n j
        -> flip maybe'
           ----
          (error "plural list")
          (just' x n j)
          acc)
    nothing'

-- Move ‘n’ & ‘j’ past ‘acc’ with ‘flip’ again:

fromSingleton
  = fromMaybe' (error "empty list")
  . foldr
    (\ x acc
      -> \ n j
        -> flip (flip maybe' (error "plural list")) acc
           ----
          (just' x n j))
    nothing'

-- Eta-reduce ‘j’ with composition:

fromSingleton
  = fromMaybe' (error "empty list")
  . foldr
    (\ x acc
      -> \ n
        -> flip (flip maybe' (error "plural list")) acc
          . just' x n)
          --
    nothing'

-- Eta-reduce ‘n’ with ‘fmap’ (to map “under” an argument):

fromSingleton
  = fromMaybe' (error "empty list")
  . foldr
    (\ x acc
      -> fmap (flip (flip maybe' (error "plural list")) acc)
         ----
        . just' x)
    nothing'

-- Move ‘x’ rightward with ‘flip’ on the outside:

fromSingleton
  = fromMaybe' (error "empty list")
  . foldr
    (flip (\ acc x
     ----
      -> fmap (flip (flip maybe' (error "plural list")) acc)
        . just' x))
    nothing'

-- Replace composition with ‘fmap’:

fromSingleton
  = fromMaybe' (error "empty list")
  . foldr
    (flip (\ acc x
      -> fmap (fmap (flip (flip maybe' (error "plural list")) acc))
         ----
        (just' x)))
    nothing'

-- Eta-reduce ‘x’ with composition:

fromSingleton
  = fromMaybe' (error "empty list")
  . foldr
    (flip (\ acc
      -> fmap (fmap (flip (flip maybe' (error "plural list")) acc))
        . just'))
        --
    nothing'

-- Replace composition with ‘fmap’:

fromSingleton
  = fromMaybe' (error "empty list")
  . foldr
    (flip (\ acc
      -> fmap (fmap (fmap (flip (flip maybe' (error "plural list")) acc)))
         ----
        just'))
    nothing'

-- Move ‘acc’ rightward with ‘flip’:

fromSingleton
  = fromMaybe' (error "empty list")
  . foldr
    (flip (\ acc
      -> flip fmap just'
         ----
        (fmap (fmap (flip (flip maybe' (error "plural list")) acc)))))
    nothing'

-- Eta-reduce with composition:

fromSingleton
  = fromMaybe' (error "empty list")
  . foldr
    (flip
      (flip fmap just'
        . fmap . fmap . flip (flip maybe' (error "plural list"))))
        --     -      -
    nothing'