Haskell printf字符串列表

Haskell printf字符串列表,haskell,string-formatting,pointfree,Haskell,String Formatting,Pointfree,我有下面的代码,用来设置电话号码的格式。(printf来自Text.printf,splitPlaces来自Data.List.Split) 我要找的是一个运算符,它允许以以下方式编写函数: prettyPrint = printf "(%s) %s-%s" <operator> splitPlaces [3, 3, 4] prettyPrint=printf“(%s)%s-%s”拆分位置[3,3,4] 是否存在这样的运营商?它真的存在吗?假设该操作符应该从列表中弹出元素并将它们

我有下面的代码,用来设置电话号码的格式。(
printf
来自Text.printf,
splitPlaces
来自Data.List.Split)

我要找的是一个运算符,它允许以以下方式编写函数:

prettyPrint = printf "(%s) %s-%s" <operator> splitPlaces [3, 3, 4]
prettyPrint=printf“(%s)%s-%s”拆分位置[3,3,4]

是否存在这样的运营商?它真的存在吗?

假设该操作符应该从列表中弹出元素并将它们逐个传递给函数,不,这是不存在的。不是真的。这当然不是一个好主意。要使其正常工作,您需要在运行时决定传递函数的参数数量,这是对类型系统的完全规避,以及它的所有好处。你可以说,清单就在这里“我不知道会有多少元素
printf
本身违反了哈斯克尔的许多哲学。它对可变签名进行类型类攻击的原因并不是允许不同数量的参数,而是不同类型的参数,这与您的情况无关

但容易实现的是从列表中获取固定数量的元素。这也不是一个好主意,因为它必须是一个部分函数。。。但这里有:

pop3 :: (a -> a -> a -> b) -> [a] -> b
pop3 f [x,y,z] = f x y z
允许你写作

printf "(%s) %s-%s" `pop3` splitPlaces [3, 3, 4] phoneNumber
实际上,我们可以概括如下:在编译时,数字仍然是固定的,但任何这样的数字都有一个单一的名称:

{-# LANGUAGE MultiParamTypeClasses  #-}
{-# LANGUAGE FlexibleInstances      #-}

class YieldsEventually f a b where
  popN :: f -> [a] -> b

instance YieldsEventually b a b where
  popN = const

instance (YieldsEventually f a b) => YieldsEventually (a->f) a b where
  popN f (x:xs) = popN (f x) xs
但是,组合两个都需要单态参数的函数来解决其自身的多态性变量可能无法很好地工作,您需要完全限定所有内容以使其编译:

(printf "(%s) %s-%s" :: String -> String -> String -> IO())
         `popN` (splitPlaces [3, 3, 4] phoneNumber :: [String])
不太好

我认为你最初的方法是最好的;显式模式还允许您插入正确的故障处理


最后,显然是最邪恶的,这里是动态参数数解决方案:

{-# LANGUAGE RankNTypes #-}

popNPrintfr :: PrintfArg a => (forall p. PrintfType p => p) -> [a] -> IO ()
popNPrintfr printr [] = printr
popNPrintfr printr (x:xs) = popNPrintfr (printr x) xs
使用起来也更简单:

printf "(%s) %s-%s" `popNPrintfr` splitPlaces [3, 3, 4] phoneNumber

如果您只想将其用于固定长度的列表,那么很容易:定义
(#)p[x,y,z]=pxyz
,然后说
printf“(%s)%s-%s”#[“000”,“111”,“2345”]
如果它是固定长度的,最好使用元组:
p#(x,y,z)=p x y z
我相信在你添加概括之前我能理解你的答案…谢谢!您可以将
popNPrintfr
的类型概括为
(printftypeq,printfarga)=>(对于所有p.printftypep=>p)->[a]->printftypeq
@kosmikus:您的意思是
…->[a] ->q
。是的,那是可能的;我想这会导致类型推断问题,比如
popN
,但实际上它似乎工作得很好。@leftaroundabout是的,很抱歉输入错误。
printf "(%s) %s-%s" `popNPrintfr` splitPlaces [3, 3, 4] phoneNumber