簡體   English   中英

具有組合映射的Haskell多態遞歸導致無限類型錯誤

[英]Haskell Polymorphic Recursion with Composed Maps causes Infinite Type Error

創建可以動態創建合成地圖的功能的正確方法是什么?

這會導致錯誤(fmap也會發生):

createComposedMaps list = accumulate list map
    where 
        accumulate (x:xs) m = accumulate xs (m.map)
        accumulate []     m = m

這個list是無關緊要的,它只是計算組合的數量。

我得到的錯誤是關於“無法構造無限類型”:

Occurs check: cannot construct the infinite type: a2 ~ [a2]
Expected type: (a2 -> b1) -> a2 -> b1
  Actual type: (a2 -> b1) -> [a2] -> [b1]
Relevant bindings include
  m :: (a2 -> b1) -> c (bound at dimensional_filter.hs:166:27)
  accumulate :: [t1] -> ((a2 -> b1) -> c) -> (a2 -> b1) -> c
    (bound at dimensional_filter.hs:166:9)
In the second argument of ‘(.)’, namely ‘map’
In the second argument of ‘accumulate’, namely ‘(m . map)’

Occurs check: cannot construct the infinite type: b1 ~ [b1]
Expected type: (a2 -> b1) -> a2 -> b1
  Actual type: (a2 -> b1) -> [a2] -> [b1]
Relevant bindings include
  m :: (a2 -> b1) -> c (bound at dimensional_filter.hs:166:27)
  accumulate :: [t1] -> ((a2 -> b1) -> c) -> (a2 -> b1) -> c
    (bound at dimensional_filter.hs:166:9)
In the second argument of ‘(.)’, namely ‘map’
In the second argument of ‘accumulate’, namely ‘(m . map)’

目標是創建一個動態組合的映射函數,我以后可以使用它。 而其他半群可以附加在一起(列表,數字......)。 功能似乎要困難得多。

非常感謝顯示fmap和/或地圖的示例。

我發現這個庫函數可以自己組合一個函數n次

但我需要使用每種中間成分,而不僅僅是最終成分。 一些例子仍然給我無限的類型錯誤。

原來問題可能涉及多態遞歸。 因為accumulate函數的每個遞歸應用都會更改地圖類型。

這是依賴類型的經典工作,這意味着我們從參數值計算返回類型。 這里我們要表示結果列表的嵌套取決於數字輸入(在您的情況下,您使用列表參數的長度作為數字輸入,但最好只使用需要數字的數字) 。

不幸的是,Haskell還沒有對依賴類型的適當支持,現有的解決方案解決方案涉及一些樣板和復雜性。 Idris是一種具有類似Haskell語法和完全依賴類型的語言,因此我可以更清晰地在Idris中說明這個想法:

-- unary naturals from the Idris Prelude :
-- data Nat = Z | S Nat

-- compose a function n times (which can also be a type constructor!)
-- for example, iterN 3 List Int = List (List (List Int))
iterN : Nat -> (a -> a) -> a -> a
iterN Z     f a = a
iterN (S k) f a = f (iterN k f a)

mapN : (n : Nat) -> (a -> b) -> iterN n List a -> iterN n List b
mapN Z     f as = f as
mapN (S k) f as = map (mapN k f) as

-- usage:
> mapN 3 (+10) [[[0]]]
[[[10]]]
> mapN 0 id 10
10

這是完整的Idris解決方案。 在Haskell中,我們不能在類型中使用值或函數,並且完成上述工作的唯一方法是創建函數的類型級版本作為類型族和類型的值級版本作為單例,有效地寫入兩倍定義是理想的。 singletons庫試圖通過模板Haskell和巧妙的機器去除大量的樣板。 這是一個基於單一的解決方案:

{-# LANGUAGE DataKinds, TypeFamilies #-}

import Data.Singletons -- package: singletons
import Data.Nat        -- package: singleton-nats (by me)

type family IterN n f a where
  IterN Z     f a = a
  IterN (S n) f a = f (IterN n f a)

mapN :: Sing n -> (a -> b) -> IterN n [] a -> IterN n [] b  
mapN SZ     f a  = f a
mapN (SS n) f as = map (mapN n f) as

-- usage:
> mapN (sing :: SLit 3) (+10) [[[0]]]
[[[10]]]

好消息是,正在進行研究和開發,以便為GHC添加依賴類型,我們可以預期在未來幾年內會有所改善。


或者,可能會嘗試使用類型類來推斷返回類型中的嵌套量。 這是相當可怕的,因為我們必須區分[a]和非列表類型,這至少需要OverlappingInstances ,但實際上它與更糟糕的IncoherentInstances可以接受,因為我們還想根據需要解決多態類型在當地的背景下。

{-# LANGUAGE
  UndecidableInstances, IncoherentInstances, MultiParamTypeClasses,
  FlexibleInstances, TypeFamilies #-}

class MapN a b as bs where
  mapN :: (a -> b) -> as -> bs

instance (as ~ a, bs ~ b) => MapN a b as bs where
  mapN = id

instance (MapN a b as bs, bs' ~ [bs]) => MapN a b [as] bs' where
  mapN f as = map (mapN f) as

-- usage:
> mapN (+1) 0
1
> mapN (+10) [[[0]]]
[[[10]]]

-- note though that without enough context `mapN`'s type is nonsense:
> :t mapN (+0)
mapN (+0) :: Num b => b -> b

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM