haskell - 将 Haskell 函数“分解”为具有各种中间类型的两个函数时如何避免重复?
问题描述
考虑以下 Haskell 代码:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TemplateHaskell #-}
import Data.Singletons.TH
singletons [d| data SimpleType = Aaa | Bbb | Ccc | Ddd
deriving (Read)
|]
-- each SimpleType value has an associated type
type family Parsed (t :: SimpleType) :: * where
Parsed Aaa = [Int]
Parsed Bbb = Maybe Int
Parsed Ccc = (Int, Int)
Parsed Ddd = Int
forth :: SSimpleType t -> Int -> Parsed t
forth SAaa x = [x,x*2,x*3]
forth SBbb x = Just x
forth SCcc x = (1337, x)
forth SDdd x = x
back :: SSimpleType t -> Parsed t -> Int
back SAaa [_, y, _] = y + 5
back SBbb (Just y) = y - 7
back SCcc (y1, y2) = y1 + y2
back SDdd y = y * 2
helper b = back b . forth b
go :: SimpleType -> Int -> Int
go Aaa = helper SAaa
go Bbb = helper SBbb
go Ccc = helper SCcc
go Ddd = helper SDdd
main = do
-- SimpleType value comes at run-time
val <- readLn
putStrLn $ show $ go val 100
定义时是否可以避免重复go
?换句话说,有没有办法写出类似的东西:
go val = helper (someMagicFunction val)
- 单身人士不必成为解决方案的一部分,
- ...但是应该保留依赖于中间类型
go
的forth
想法。back
Simple
解决方案
您可以使用toSing
fromSingKind
将 的值转换为SimpelType
的值SomeSing SimpleType
,这是对 的存在量化包装Sing SimpleType
。然后,您可以打开该值以获得 get Sing SimpleType
,然后您可以将其传递给back
and forth
:
go :: SimpleType -> Int -> Int
go val x =
case toSing val of
SomeSing s -> back s $ forth s x
您正在使用的拼接会SingKind
为您(以及许多其他事情)生成一个实例。singletons
请注意,虽然单分支case
要求成为 a let
,但这不会编译:
go val x =
let (SomeSing s) = toSing val
in back s $ forth s x
这是被禁止的,因为let
它可能是递归的,并且由于解包 GADT 可能会将新类型带入上下文,它可能会导致创建无限类型。另一方面,case
分支不能递归,所以这是可行的。(此解释归功于@HTNW)
但是辅助函数也可以工作:
go val x = helper $ toSing val
where
helper (SomeSing s) = back s $ forth s x
推荐阅读
- php - laravel 为内核中的运行命令设置时间表
- react-native - 如何将动态 URL 设置为 webview?
- javascript - 保存“办公时间”数据的正确方法是什么?
- python - 合并数据框不是基于索引而是值
- asp.net - 链接到 GridView asp 中的虚拟目录:HyperlinkField
- php - Laravel 7.15 视图中的 UUID 无法正确显示
- android - 如果单击开始按钮,则不会继续
- reactjs - React-plotly:带有选择器的时间序列范围滑块的滑动速度很慢
- java - ServerSocket 中的 accept() 接受客户端请求的速度有多快?
- mongodb - 如何在mongo中使用IN运算符和RANGE