Haskell的自然转变是什么?

zer*_*ing 5 haskell

我想知道,Haskell中的自然转变是什么。自然转换用以下签名描述:

F[a] ~> G[a]
Run Code Online (Sandbox Code Playgroud)

例如,我可以转换:

Maybe a ~> List a
Run Code Online (Sandbox Code Playgroud)

对?

那怎么IO做是不可能的呢?
自然转型的目的是什么?

che*_*ner 5

自然转换,而无需深入了解其背后的类别理论,实际上只是一个多态函数。

Prelude> :set -XRankNTypes
Prelude> :set -XTypeOperators
Prelude> type (~>) f g = forall x. f x -> g x
Run Code Online (Sandbox Code Playgroud)

~>操作映射类型构造为另一种类型的构造,在这样一种方式,它适用于任何给定参数的第一类构造函数。TypeOperator扩展名是我们可以使用的扩展名,~>而不是NatTrans; 该RankNTypes是什么让我们使用forall的定义,以便调用者可以选择哪种类型的fg将被应用到。

这里是从天然变换的例子MaybeList,需要一个Maybe a用于任何类型的a,并产生一个等效列表(通过返回一个空列表或包裹值作为单列表)。

Prelude> :{
Prelude| m2l :: Maybe ~> []
Prelude| m2l Nothing = []
Prelude| m2l (Just x) = [x]
Prelude| :}
Prelude> m2l Nothing
[]
Prelude> m2l (Just 3)
[3]
Prelude> m2l (Just 'c')
"c"
Run Code Online (Sandbox Code Playgroud)

l2m :: [] ~> Maybel2m [] = Nothing和的“逆”将是l2m (x:_) = Just x。(我将引号取反,因为m2l (l2m [1,2,3]) /= [1,2,3]

没有什么可以阻止您IO用作任何一种类型构造函数(尽管如果IO在左侧,则它也必须在右侧)。

foo :: IO ~> IO
foo a = putStrLn "hi" >> a
Run Code Online (Sandbox Code Playgroud)

然后

> foo (putStrLn "foo")
hi
foo
> foo (return 3)
hi
3
Run Code Online (Sandbox Code Playgroud)

另一个示例将length视为从[]到的自然转变Const Int(改编自https://bartoszmilewski.com/2015/04/07/natural-transformations/,我强烈建议阅读):

-- Isomorphic to builtin length, as Const Int is isomorphic to Int
-- Requires importing Data.Functor.Const
length' :: [] ~> Const Int
length' [] = Const 0
length' (x:xs) = Const (1 + getConst (length' xs))
Run Code Online (Sandbox Code Playgroud)


lef*_*out 5

在这里明确是有用的:自然转换是签名的函数

? :: ? a . ? a -> ? a
Run Code Online (Sandbox Code Playgroud)

where??是函子。的?当然是在Haskell暗示的,但是这确实是关于自然变换的关键的东西。那和交换图

自然变换的交换图

即在 Haskell 中,

(fmap f :: ? x -> ? y) . (? :: ? x -> ? x)
           ? (? :: ? y -> ? y) . (fmap f :: ? x -> ? y)
Run Code Online (Sandbox Code Playgroud)

或简称,fmap f . ? ? ? . fmap f。(但请注意,两者?在这里都有不同的类型!)

例如,我可以转换:

也许一个 ~> 列出一个

嗯,yyyea...ish。再次,明确你的意思。具体来说,以下是从Maybeto的自然转换[](这不是Maybe ato的自然转换[a],这是没有意义的):

maybeToList :: Maybe a -> [a]
maybeToList Nothing = []
maybeToList (Just a) = [a]
Run Code Online (Sandbox Code Playgroud)

但这并不是唯一的这种转变。事实上有?许多这样的转换,例如

maybeToList9 :: Maybe a -> [a]
maybeToList9 Nothing = []
maybeToList9 (Just a) = [a,a,a,a,a,a,a,a,a]
Run Code Online (Sandbox Code Playgroud)

怎么样IO,自然转化是不可能的吧?

这也是可能的。例如,这是从NonEmpty到的自然转换IO

import qualified Data.List.NonEmpty as NE
import System.Exit (die)

selectElem :: NonEmpty a -> IO a
selectElem l = do
   let len = NE.length l
   putStrLn $ "Which element? (Must be <"++show len++")"
   i <- readLine
   if i<len then die "Index too big!"
            else return $ l NE.! i
Run Code Online (Sandbox Code Playgroud)