如何在Morte中输入zipWith?

时间:2016-11-17 02:27:36

标签: haskell functional-programming agda dependent-type morte

这是Morte中几乎有效的zipWith定义:

zipWith
  =  λ (u : *)
  -> λ (f : (u -> u -> u))
  -> λ (a : (#List u))
  -> λ (b : (#List u))
  -> λ (List : *)
  -> λ (cons : (u -> List -> List))
  -> λ (nil : List)
  -> ((λ (A:*) -> λ (B:*) ->
  (a (B -> List)
    (λ (h:u) -> λ (t : (B -> List) -> λ k : B -> (k h t)))
    (λ (k:B) -> nil)
    (b (u -> A -> List)
      (λ (h:u) -> λ (t:(u -> A -> List)) -> λ (H:u) -> λ (k:A) -> (cons (f h H) (k t)))
      (λ (H:u) -> λ (k:A) -> nil)))
  ) (fix A . ((u -> A -> List) -> List))
    (fix B . (u -> (B -> List) -> List)))

由于Morte缺少使用fix,因此实际上并不是可输入的。 András posted this clever Agda solution without fix去年。然而,对我而言,它如何转化为Morte并不明显,因为它也缺乏归纳类型。如何解决这个问题?

编辑:使用fix似乎我的zipWith不正确。 This one似乎在检查。

2 个答案:

答案 0 :(得分:6)

为简单起见,我将使用常规的Haskell列表。首先,让我们使用zipWith定义foldr

zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c]
zipWith' f xs ys = foldr step (const []) xs ys where
  step x r  []    = []
  step x r (y:ys) = f x y : r ys

这里我们折叠xs,传递ys作为参数,并在每次迭代时拆分它。问题是我们想要模仿教会编码的列表,但它们不能模式匹配。但是,可以定义split

split :: [a] -> Maybe (a, [a])
split  []    = Nothing
split (x:xs) = Just (x, xs)

foldr而言:

split :: [a] -> Maybe (a, [a])
split = snd . foldr (\x ~(r, _) -> (x : r, Just (x, r))) ([], Nothing)

现在我们只能使用正确的折叠来定义zipWith

czipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
czipWith f xs ys = foldr step (const []) xs ys where
  step x r = maybe [] (\(y, ys) -> f x y : r ys) . split

然而,虽然split懒惰地遍历列表(所以split [1..] ≡ Just (1, [2..])),但它仍然解构并重建整个列表,因此每个split引入了O(n)开销,其中{ {1}}是要拆分的列表的长度。由于n在每次迭代时被分割,因此算法的总复杂度为O(n ^ 2)。

所以是的,您可以只使用非递归类型键入ys,但它将是O(n ^ 2)。

此外,消除器是依赖的​​paramorphisms和paramorphisms确实给你模式匹配,所以如果你有消除器,它是straightforward来定义O(n)zipWith并且它不必那么复杂如在András'回答你链接。

一些阅读:

答案 1 :(得分:4)

fix的聪明定义(来自Launchbury et al.,我相信)在Morte中不起作用,因为键入它而没有负面的递归类型(Morte没有,这意味着什么) O(N^2),如我之前的mentioned回答中所述),至少需要对自然数进行归纳。 Here's一个简单的Agda版本的Launchbury定义没有教会编码;要在Morte中重现这一点,我们需要的函数的返回类型取决于自然数(输入列表的长度)。

如果没有归纳,我们可以做的最好的是O(N)定义,在列表上使用List A -> Maybe (A, List A)模式匹配,i。即一个O(N)函数。它是let,因为我们只能通过从最后重建它来获得列表的尾部。

在Morte兼容的Agda中(为了获得Morte,我们需要将Pair : Set → Set → Set Pair A B = ∀ P → (A → B → P) → P pair : ∀ A B → A → B → Pair A B pair A B a b P p = p a b List : Set → Set List = λ A → ∀ L → (A → L → L) → L → L Maybe : Set → Set Maybe A = ∀ M → (A → M) → M → M just : ∀ A → A → Maybe A just A a M j n = j a nothing : ∀ A → Maybe A nothing A M j n = n nil : ∀ A → List A nil A L c n = n cons : ∀ A → A → List A → List A cons A a as L c n = c a (as L c n) match : ∀ A → List A → Maybe (Pair A (List A)) match A as = as (Maybe (Pair A (List A))) (λ a m M j n → m M (λ p → p M (λ a' as → j (pair A (List A) a (cons A a' as)))) (j (pair A (List A) a (nil A)))) (nothing (Pair A (List A))) zipWith : ∀ A B C → (A → B → C) → List A → List B → List C zipWith A B C f as = as (List B → List C) (λ a hyp bs → match B bs (List C) (λ p → p (List C) (λ b bs' → cons C (f a b) (hyp bs'))) (nil C)) (λ _ → nil C) 样式定义去除应用程序和函数定义到注释的lambdas):

     import javax.swing.*;
     import java.awt.*;

     class calculator{
     public static void main(String args[])
     {
         JFrame frame=new JFrame("Simple Calculator");
         JPanel mainpanel=new JPanel();

         JPanel tfpanel=new JPanel();
         JTextField tf=new JTextField();
         tfpanel.add(tf);
         tfpanel.setSize(200,40);
         tfpanel.setLayout(new GridLayout(0,1));