Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.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 - Fatal编程技术网

Haskell 如何为函子制作点(合成)和美元(应用)符号?

Haskell 如何为函子制作点(合成)和美元(应用)符号?,haskell,Haskell,我为函子做了点符号(○), 但是我的申请(↯) 不工作,我在test3函数声明中有一个错误 {-# LANGUAGE TypeOperators #-} module Main where import Protolude -- composition of functors, analog of . infixr 9 ○ type (○) f g a = f (g a) -- functor application, analog of $ infixr 0 ↯ type (↯) f

我为函子做了点符号(○), 但是我的申请(↯) 不工作,我在
test3
函数声明中有一个错误

{-# LANGUAGE TypeOperators #-}

module Main where

import Protolude

-- composition of functors, analog of .
infixr 9 ○
type (○) f g a = f (g a)

-- functor application, analog of $
infixr 0 ↯
type (↯) f a = f a

test :: [] (Maybe Int)
test = [Just 1]

test2 :: ([] ○ Maybe) Int
test2 = [Just 1]

test3 :: ([] ○ Maybe) ↯ Int -- error here
test3 = [Just 1]

main :: IO ()
main = do
  print test
  print test2
  return ()
我有个错误

[Error]• The type synonym ‘○’ should have 3 arguments, but has been given 2 • In the type signature: test3 :: ([] ○ Maybe) ↯ Int
怎么了


更新

这里是使用newtype的实现,因为不能部分应用
类型同义词(@M.Aroosi)

我不喜欢它,因为我必须一直用数据类型构造函数包装数据

有没有一种方法可以实现它,而不需要始终使用
组合
应用
包装数据?

{-# LANGUAGE TypeOperators #-}

module Main where

import Protolude

-- I can't use `type` here, because type synonyms cannot be partially applied

-- composition of functors, analog of .
infixr 9 ○
newtype (○) f g a = Composition (f (g a)) deriving (Show)

-- functor application, analog of $
infixr 0 ↯
newtype (↯) f a = Apply (f a) deriving (Show)

test :: [] (Maybe Int)
test = [Just 1]

test2 :: ([] ○ Maybe) Int
test2 = Composition [Just 1]

test2' :: [] ○ Maybe ↯ Int
test2' = Apply (Composition [Just 1])

test3 :: ([] ○ Maybe ○ Maybe) Int
test3 = Composition [Composition (Just (Just 1))]

test3' :: [] ○ Maybe ○ Maybe ↯ Int
test3' = Apply (Composition [Composition (Just (Just 1))])

main :: IO ()
main = do
  print test
  print test2
  print test2'
  print test3
  print test3'
  return ()

更新

这可以在idris中轻松完成

module Main

test : List (Maybe Integer)
test = [Just 1]

-- using (.) from prelude
test1 : (List . Maybe) Integer
test1 = [Just 1]

-- using (.) and ($) from prelude
test2 : List . Maybe $ Integer
test2 = [Just 1]

main : IO ()
main = do
  print test
  print test1
  print test2

更新

使用
类型的组合也可以在purescript中使用(耶!)


更新

haskell正在努力使这成为可能


因此,根据您的要求,这里是一个涉及类型族的解决方案。它基于软件包背后的思想,并附有一篇解释该思想的文章

在我开始之前,有一点是赞成使用普通数据类型/newtype的:您可以为合成类型定义函子实例,使其作为单个单元,也就是说,您可以定义
实例(函子f,函子g)=>函子(合成f g),其中..
,这是使用下面的方法无法做到的。
可能有一个库允许您使用类型列表而不仅仅是2(因此类似于
Compose[Maybe,[],或Int]a
),但我现在似乎找不到它,因此如果有人知道它,它可能是一个比我下面介绍的更好的解决方案(在我看来)

首先,我们需要一些语言扩展:

{-# LANGUAGE 
  TypeFamilies,
  TypeInType,
  TypeOperators
  #-}
我们还包括
类型的
数据.Kind

import Data.Kind (Type)
让我们定义一个类型
expa
,它将表示
a

我们还将定义一个类型族
Eval
,它将执行繁重的工作,它将需要
Exp a
并给我们一个
a

type Exp a = a -> Type
type family Eval (e :: Exp a) :: a
现在我们可以定义运算符
(○)
(↯)
(我更喜欢在这里使用更容易键入的运算符,比如#和$,但我会使用您为这个答案选择的运算符)。
我们将它们定义为空数据类型。这就是
TypeInType
的作用(和
TypeOperators
但这是因为我们使用的是运算符)

请注意,对于他们来说,最后一种是
expa
,这允许我们为他们提供
Eval

type instance Eval ((○) f g a) = f (Eval (g a))
type instance Eval ((↯) f a) = Eval (f a)
现在您可能想知道“
(○)
的第二个参数是类
a->Exp b
,但我想给它一些类似
的东西,它有类
*->*
!”,这就是我们有3种解决方案的地方:

  • 添加另一个操作符,例如
    (%)
    ,与
    (○)
    但采用第二种类型的参数
    a->b
    ,而不是
    a->Exp b
    。这只需要替换最右边的合成运算符
  • “提升”类
    a->b
    a->Exp b
    ,我将使用名为
    lift
    的数据类型。这只需要对组合中最右边的类型执行
  • 提供一种“不做任何事情”的数据类型
    a->Exp b
    ,我将其称为
  • 以下是用Haskell编写的三种解决方案:

    infixr 9 %
    data (%) :: (b -> c) -> (a -> b) -> a -> Exp c
    type instance Eval ((%) f g a) = f (g a)
    
    data Lift :: (a -> b) -> a -> Exp b
    type instance Eval (Lift f a) = f a
    
    data Pure :: a -> Exp a
    type instance Eval (Pure a) = a 
    
    使用这个设置,我们可以做的另一件事是创建一个类型级别的函数datatype,我们称之为“Compose”,它将获取一个类型列表并生成它们的组合

    data Compose :: [a -> a] -> a -> Exp a 
    type instance Eval (Compose '[] a) = a
    type instance Eval (Compose (x:xs) a) = x (Eval (Compose xs a))
    
    现在我们可以通过一些测试和一个只打印测试值的
    main
    来制作程序:

    {-# LANGUAGE 
      TypeFamilies,
      TypeInType,
      TypeOperators
      #-}
    
    module Main where
    
    import Data.Kind (Type)
    
    type Exp a = a -> Type
    type family Eval (e :: Exp a) :: a
    
    infixr 9 ○
    data (○) :: (b -> c) -> (a -> Exp b) -> a -> Exp c
    
    infixr 0 ↯
    data (↯) :: (a -> Exp b) -> a -> Exp b
    
    type instance Eval ((○) f g a) = f (Eval (g a))
    type instance Eval ((↯) f a) = Eval (f a)
    
    infixr 9 %
    data (%) :: (b -> c) -> (a -> b) -> a -> Exp c
    type instance Eval ((%) f g a) = f (g a)
    
    data Lift :: (a -> b) -> a -> Exp b
    type instance Eval (Lift f a) = f a
    
    data Pure :: a -> Exp a
    type instance Eval (Pure a) = a 
    
    data Compose :: [a -> a] -> a -> Exp a 
    type instance Eval (Compose '[] a) = a
    type instance Eval (Compose (x:xs) a) = x (Eval (Compose xs a))
    
    test :: [] (Maybe Int)
    test = [Just 1]
    
    -- using %
    test2 :: Eval (([] % Maybe) Int)
    test2 = [Just 1]
    
    test2' :: Eval ([] % Maybe ↯ Int)
    test2' = [Just 1]
    
    -- works for longer types too
    test3 :: Eval (([] ○ Maybe % Maybe) Int)
    test3 = [Just (Just 1)]
    
    test3' :: Eval ([] ○ Maybe % Maybe ↯ Int)
    test3' = [Just (Just 1)]
    
    -- we can instead Lift the rightmost type
    test4 :: Eval (([] ○ Maybe ○ Lift Maybe) Int)
    test4 = [Just (Just 1)]
    
    test4' :: Eval ([] ○ Maybe ○ Lift Maybe ↯ Int)
    test4' = [Just (Just 1)]
    
    -- an even longer type, with definition "matching" the type declaration
    test5 :: Eval ([] ○ Maybe ○ Either Bool % Maybe ↯ Int)
    test5 = (:[]) . Just . Right . Just $ 1
    
    -- Same as above, but instead let's use Pure so we don't need to lift the Maybe or use %
    test6 :: Eval ([] ○ Maybe ○ Either Bool ○ Maybe ○ Pure ↯ Int)
    test6= (:[]) . Just . Right . Just $ 1
    
    -- same as above, uses Compose
    test7 :: Eval (Compose [[], Maybe, Either Bool, Maybe] Int)
    test7= (:[]) . Just . Right . Just $ 1
    
    main :: IO ()
    main = do
      print test
      print test2
      print test2'
      print test3
      print test3'
      print test4
      print test4'
      print test5
      print test6
      print test7
      return ()
    

    @M.Aroosi(我看到你删除了你的评论)非常糟糕,
    类型同义词不能部分应用
    ,每次我都必须将我的对象包装在数据类型构造函数
    组合
    应用
    中时,代码看起来很难看(发布了答案).有没有一种方法可以实现无需
    数据
    新类型
    的函子合成?有没有一种方法可以实现函子合成,而无需始终包装在数据构造函数
    合成
    应用
    中?例如,在idris中是否可以使用类型同义词?有一种使用类型族之类的解决方案,但它涉及使用类型签名,如
    Eval([]○ 大概○ 也许可以举起来↯ Int)
    ,或者如果您希望为最后一个(好吧,因为它与右侧关联,所以是第一个)组合引入另一个运算符:
    Eval([]○ 也许%也许↯ Int)
    如果这符合您的要求,请告诉我,我会将其作为答案发布。@M.Aroosi是的,请发布一个答案:)我想补充的一点是,
    Fcf
    包已经定义了其中的大部分内容,您只需要在答案中添加一些内容:合成操作符,应用程序操作符,如果您想要unicode lightning(在
    Fcf
    中已经有一个,他们只需使用
    ($)
    )在
    Fcf
    中,他们将我命名的
    Lift
    称为
    Pure1
    ,您也可以使用fish操作符
    对常见问题的意外答案tnx
    
    data Compose :: [a -> a] -> a -> Exp a 
    type instance Eval (Compose '[] a) = a
    type instance Eval (Compose (x:xs) a) = x (Eval (Compose xs a))
    
    {-# LANGUAGE 
      TypeFamilies,
      TypeInType,
      TypeOperators
      #-}
    
    module Main where
    
    import Data.Kind (Type)
    
    type Exp a = a -> Type
    type family Eval (e :: Exp a) :: a
    
    infixr 9 ○
    data (○) :: (b -> c) -> (a -> Exp b) -> a -> Exp c
    
    infixr 0 ↯
    data (↯) :: (a -> Exp b) -> a -> Exp b
    
    type instance Eval ((○) f g a) = f (Eval (g a))
    type instance Eval ((↯) f a) = Eval (f a)
    
    infixr 9 %
    data (%) :: (b -> c) -> (a -> b) -> a -> Exp c
    type instance Eval ((%) f g a) = f (g a)
    
    data Lift :: (a -> b) -> a -> Exp b
    type instance Eval (Lift f a) = f a
    
    data Pure :: a -> Exp a
    type instance Eval (Pure a) = a 
    
    data Compose :: [a -> a] -> a -> Exp a 
    type instance Eval (Compose '[] a) = a
    type instance Eval (Compose (x:xs) a) = x (Eval (Compose xs a))
    
    test :: [] (Maybe Int)
    test = [Just 1]
    
    -- using %
    test2 :: Eval (([] % Maybe) Int)
    test2 = [Just 1]
    
    test2' :: Eval ([] % Maybe ↯ Int)
    test2' = [Just 1]
    
    -- works for longer types too
    test3 :: Eval (([] ○ Maybe % Maybe) Int)
    test3 = [Just (Just 1)]
    
    test3' :: Eval ([] ○ Maybe % Maybe ↯ Int)
    test3' = [Just (Just 1)]
    
    -- we can instead Lift the rightmost type
    test4 :: Eval (([] ○ Maybe ○ Lift Maybe) Int)
    test4 = [Just (Just 1)]
    
    test4' :: Eval ([] ○ Maybe ○ Lift Maybe ↯ Int)
    test4' = [Just (Just 1)]
    
    -- an even longer type, with definition "matching" the type declaration
    test5 :: Eval ([] ○ Maybe ○ Either Bool % Maybe ↯ Int)
    test5 = (:[]) . Just . Right . Just $ 1
    
    -- Same as above, but instead let's use Pure so we don't need to lift the Maybe or use %
    test6 :: Eval ([] ○ Maybe ○ Either Bool ○ Maybe ○ Pure ↯ Int)
    test6= (:[]) . Just . Right . Just $ 1
    
    -- same as above, uses Compose
    test7 :: Eval (Compose [[], Maybe, Either Bool, Maybe] Int)
    test7= (:[]) . Just . Right . Just $ 1
    
    main :: IO ()
    main = do
      print test
      print test2
      print test2'
      print test3
      print test3'
      print test4
      print test4'
      print test5
      print test6
      print test7
      return ()